美文网首页
基于@AspectJ注解进行AOP编程

基于@AspectJ注解进行AOP编程

作者: NisyCoding | 来源:发表于2020-06-15 19:55 被阅读0次

    一. 基于注解的AOP变成开发步骤

    • 原始对象
    • 额外功能
    • 切入点
    • 组装切面

    二. 开发步骤

    2.1 创建带有@Aspect的切面类

    package com.baizhiedu.aspectj;
    
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    /**
     * 通过切面类定义额外功能,@Around注解,同时也定义了切入点,around当中的参数
     */
    
    /**
     * @Aspect注解:
     * 表示这是一个切面类:额外功能+切入点
     * 作用等同于:实现MethodInterceptor接口,重写invoke方法
     */
    
    /**
     * @Aroud注解:
     * 相当有之前的额外功能,around()等同于invoke()
     */
    
    
    @Aspect
    public class MyAspectJ {
    
        @Around("execution(* login(..))")
        public Object arround(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("注解额外功能...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    
    }
    
    

    @Aspect注解:表示这是一个切面类,切面类需要包含:切入点+额外功能

    2.2 添加额外功能

    之前,我们创建的额外功能,是基于MethodInterceptor接口,实现该接口,重写接口中的invoke(),在invoke方法中实现了原始方法的运行+额外功能的编写;
    如今,我们需要在需要额外功能的方法上,添加@Around注解,然后方法参数:ProceddingJoinPoint,这里就相当于之前invoke方法中的MethodInvocation.

        @Around("暂时这里不需要填写")
        public Object arround(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("注解额外功能...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    

    2.3 配置切入点

    @Around("execution(* login(..))")
    

    2.4 初始化切面对象.MyAspect

        <bean class="com.baizhiedu.aspectj.MyAspectJ" id="around"></bean>
    

    2.5 重点:告诉spring,我们是基于注解开发的

    <!--    告诉spring,我们是基于注解开发的-->
        <aop:aspectj-autoproxy/>
    

    三. 测试结果:

    注解额外功能...
    UserServiceImpl.login
    UserServiceImpl.register
    

    四. 完成代码:

    4.1 UserService

    package com.baizhiedu.aspectj;
    
    import com.baizhiedu.proxy.User;
    
    public interface UserService {
    
        void login(String name, int age);
    
        void register(User user);
    }
    

    4.2 UserServiceImpl

    package com.baizhiedu.aspectj;
    
    
    import com.baizhiedu.proxy.User;
    
    /**
     * 原始对象
     */
    public class UserServiceImpl implements UserService {
    
    
        public void login(String name, int age) {
            System.out.println("UserServiceImpl.login");
        }
    
        public void register(User user) {
            System.out.println("UserServiceImpl.register");
        }
    }
    

    4.3 MyAspect切面类:

    package com.baizhiedu.aspectj;
    
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    /**
     * 通过切面类定义额外功能,@Around注解,同时也定义了切入点,around当中的参数
     */
    
    /**
     * @Aspect注解:
     * 表示这是一个切面类:额外功能+切入点
     * 作用等同于:实现MethodInterceptor接口,重写invoke方法
     */
    
    /**
     * @Aroud注解:
     * 相当有之前的额外功能,around()等同于invoke()
     */
    
    
    @Aspect
    public class MyAspectJ {
    
        @Around("execution(* login(..))")
        public Object arround(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("注解额外功能...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    
    }
    

    4.4 ApplicationContext.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
        <bean id="userService" class="com.baizhiedu.aspectj.UserServiceImpl"></bean>
    
        <bean class="com.baizhiedu.aspectj.MyAspectJ" id="around"></bean>
    
    <!--    告诉spring,我们是基于注解开发的-->
        <aop:aspectj-autoproxy/>
    
    </beans>
    

    4.5 Test测试文件

    package com.baizhiedu.aspectj;
    
    import com.baizhiedu.proxy.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
    
        public static void main(String[] args) {
            ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext7.xml");
            UserService userService = (UserService) ctx.getBean("userService");
            userService.login("Nisy",20);
            userService.register(new User());
        }
    }
    

    5. 基于注解的AOP编程注意事项:

    5.1 细节1:切入点复用

    一个切面类中,有可能出现一个log的额外功能,一个事务等多个额外功能,此时我们怎么办?死办法就是,如下:

    package com.baizhiedu.aspectj;
    
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    
    /**
     * 通过切面类定义额外功能,@Around注解,同时也定义了切入点,around当中的参数
     */
    
    /**
     * @Aspect注解:
     * 表示这是一个切面类:额外功能+切入点
     * 作用等同于:实现MethodInterceptor接口,重写invoke方法
     */
    
    /**
     * @Aroud注解:
     * 相当有之前的额外功能,around()等同于invoke()
     */
    
    
    @Aspect
    public class MyAspectJ {
       @Around("execution(* login(..))")
       public Object arround(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("注解额外功能...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    
        @Around("execution(* login(..))")
        public Object arround1(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("事务...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    
    }
    

    观察以上代码,我们发现,代码出现了冗余,该怎么办呢?怎么进行代码复用呢?
    答:基于注解@JonintCut定义切入点方法.没有代码块,没有返回值

        @Pointcut("execution(* login(..))")
        public void pointCut(){}
    
    package com.baizhiedu.aspectj;
    
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    
    /**
     * 通过切面类定义额外功能,@Around注解,同时也定义了切入点,around当中的参数
     */
    
    /**
     * @Aspect注解:
     * 表示这是一个切面类:额外功能+切入点
     * 作用等同于:实现MethodInterceptor接口,重写invoke方法
     */
    
    /**
     * @Aroud注解:
     * 相当有之前的额外功能,around()等同于invoke()
     */
    
    
    @Aspect
    public class MyAspectJ {
    
        //切入点复用:在切面类中定义一个函数,上面@PointCut注解,通过这种方式,定义切入点表达式,后续更加有利于切入点复用
        @Pointcut("execution(* login(..))")
        public void pointCut(){}
    
    
    //    @Around("execution(* login(..))")
        @Around(value = "pointCut()")
        public Object arround(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("注解额外功能...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    
        @Around(value = "pointCut()")
    //    @Around("execution(* login(..))")
        public Object arround1(ProceedingJoinPoint proceedingJoinPoint){
            try {
                System.out.println("事务...");
                Object proceed = proceedingJoinPoint.proceed();
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    
    }
    
    

    结果显示:

    C:\Tools\jdk1.8\bin\java.exe -javaagent:D:\Browser-DownLoad\ideaIU-2019.3.win\lib\idea_rt.jar=56822:D:\Browser-DownLoad\ideaIU-2019.3.win\bin -Dfile.encoding=UTF-8 -classpath C:\Tools\jdk1.8\jre\lib\charsets.jar;C:\Tools\jdk1.8\jre\lib\deploy.jar;C:\Tools\jdk1.8\jre\lib\ext\access-bridge-64.jar;C:\Tools\jdk1.8\jre\lib\ext\cldrdata.jar;C:\Tools\jdk1.8\jre\lib\ext\dnsns.jar;C:\Tools\jdk1.8\jre\lib\ext\jaccess.jar;C:\Tools\jdk1.8\jre\lib\ext\jfxrt.jar;C:\Tools\jdk1.8\jre\lib\ext\localedata.jar;C:\Tools\jdk1.8\jre\lib\ext\nashorn.jar;C:\Tools\jdk1.8\jre\lib\ext\sunec.jar;C:\Tools\jdk1.8\jre\lib\ext\sunjce_provider.jar;C:\Tools\jdk1.8\jre\lib\ext\sunmscapi.jar;C:\Tools\jdk1.8\jre\lib\ext\sunpkcs11.jar;C:\Tools\jdk1.8\jre\lib\ext\zipfs.jar;C:\Tools\jdk1.8\jre\lib\javaws.jar;C:\Tools\jdk1.8\jre\lib\jce.jar;C:\Tools\jdk1.8\jre\lib\jfr.jar;C:\Tools\jdk1.8\jre\lib\jfxswt.jar;C:\Tools\jdk1.8\jre\lib\jsse.jar;C:\Tools\jdk1.8\jre\lib\management-agent.jar;C:\Tools\jdk1.8\jre\lib\plugin.jar;C:\Tools\jdk1.8\jre\lib\resources.jar;C:\Tools\jdk1.8\jre\lib\rt.jar;E:\myproject\spring5.x\target\classes;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-context\5.1.4.RELEASE\spring-context-5.1.4.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-beans\5.1.4.RELEASE\spring-beans-5.1.4.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-core\5.1.4.RELEASE\spring-core-5.1.4.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-jcl\5.1.4.RELEASE\spring-jcl-5.1.4.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-expression\5.1.4.RELEASE\spring-expression-5.1.4.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-webmvc\5.1.14.RELEASE\spring-webmvc-5.1.14.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-web\5.1.14.RELEASE\spring-web-5.1.14.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\WorkTools\apache-maven-3.2.3\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\WorkTools\apache-maven-3.2.3\repository\mysql\mysql-connector-java\5.1.48\mysql-connector-java-5.1.48.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\springframework\spring-aop\4.3.27.RELEASE\spring-aop-4.3.27.RELEASE.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\aspectj\aspectjrt\1.9.5\aspectjrt-1.9.5.jar;D:\WorkTools\apache-maven-3.2.3\repository\org\aspectj\aspectjweaver\1.9.5\aspectjweaver-1.9.5.jar com.baizhiedu.aspectj.Test
    2020-06-16 12:38:00 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6d9c638
    2020-06-16 12:38:01 DEBUG XmlBeanDefinitionReader:395 - Loaded 3 bean definitions from class path resource [applicationContext7.xml]
    2020-06-16 12:38:01 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
    2020-06-16 12:38:01 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService'
    2020-06-16 12:38:01 DEBUG ReflectiveAspectJAdvisorFactory:250 - Found AspectJ method: public java.lang.Object com.baizhiedu.aspectj.MyAspectJ.arround(org.aspectj.lang.ProceedingJoinPoint)
    2020-06-16 12:38:01 DEBUG ReflectiveAspectJAdvisorFactory:250 - Found AspectJ method: public java.lang.Object com.baizhiedu.aspectj.MyAspectJ.arround1(org.aspectj.lang.ProceedingJoinPoint)
    2020-06-16 12:38:01 DEBUG AnnotationAwareAspectJAutoProxyCreator:521 - Creating implicit proxy for bean 'userService' with 0 common interceptors and 3 specific interceptors
    2020-06-16 12:38:01 DEBUG JdkDynamicAopProxy:118 - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.baizhiedu.aspectj.UserServiceImpl@366647c2]
    2020-06-16 12:38:01 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'around'
    注解额外功能...
    事务...
    UserServiceImpl.login
    UserServiceImpl.register
    

    5.2 细节2:动态代理的创建方式:

    我们可以在测试类中,打一个端点,看一下,我们拿到的对象,在默认情况下是基于哪一种动态代理呢?下面就验证一下:


    image.png

    默认情况下,AOP底层的动态代理是基于:"JDK动态代理"

    5.2.1 我们可以改变AOP默认的动态代理吗?

    可以的,我们在基于注解的情况下,可以在applicationContext.xml配置文件中修改:

    <!--    告诉spring,我们是基于注解开发的  proxy-target-class为true,就是把jdk换成cglib代理-->
        <aop:aspectj-autoproxy proxy-target-class="true"/>
    

    5.2.2 如果我们没有基于注解开发,那怎么办呢?

    //proxy-target-class="true 就是把jdk动态代理换成cglib动态代理
        <aop:config proxy-target-class="true">
    <!--        配置切入点-->
    <!--        <aop:pointcut id="pc" expression="execution(* *(..))"/>-->
    <!--        <aop:pointcut id="pc" expression="execution(* com.baizhiedu.proxy.UserServiceImpl.login(..))"/>-->
            <aop:pointcut id="pc" expression="@annotation(com.baizhiedu.proxy.Log)"/>
            <!--        配置切面 整合什么? 整合额外功能-->
            <aop:advisor advice-ref="arroud" pointcut-ref="pc"/>
        </aop:config>
    

    相关文章

      网友评论

          本文标题:基于@AspectJ注解进行AOP编程

          本文链接:https://www.haomeiwen.com/subject/dwmhxktx.html