Spring之AOP

作者: cslrx | 来源:发表于2017-05-09 20:03 被阅读0次

    前言

    继续引用上一篇博客的代码(Spring之IOC

    源代码目录结构如下:

    main
        service
            UserService
        dao
            UserDao(接口)
            UserDaoImpl
        model
            User
        beans.xml
    

    日志引发的问题

    如果有这样一个需求:在保存用户到数据库之前添加日志,怎么做?

    • 直接修改源代码
    • 继承,重写方法
    • 组合,装饰者模式

    如果有几百个方法等着我们去加日志,怎么办?
    Spring为我们提供了一种方法:面向切面编程,也就是传说中的AOP。
    在谈AOP之前,我们简单谈一下JDK中动态代理的实现方式,AOP就是通过动态代理技术实现面向切面编程的。

    动态代理

    在日志问题中,我们也可以通过动态代理实现。
    代理充当着一个中间人的角色,在使用代理时我们可以执行一些额外操作,Java的动态代理可以动态的处理方法调用,将所有对方法的调用重定向到单一的调用处理器上。
    代码如下:
    测试代码

    @Test
    public void testProxy() {
        UserDao userDao = new UserDaoImpl();
        // 获得一个动态代理
        UserDao proxy = (UserDao)Proxy.newProxyInstance(
                userDao.getClass().getClassLoader(),
                new Class[]{UserDao.class},
                new DynamicProxyHandle(userDao));
        proxy.save(new User());
    }
    

    事件处理类

    public class DynamicProxyHandle  implements InvocationHandler{
        private Object target;// 代理目标
    
        public DynamicProxyHandle(Object target) {// 通过构造方法传参
            this.target = target;
        }
        // 所有对目标的方法调用都会重定向到此方法上
        // 故我们可以在原方法执行之前或之后添加一些逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("动态代理中");
            return method.invoke(target,args);
        }
    }
    

    Spring AOP

    先不说AOP的核心概念,我们看一下通过Spring AOP怎么实现日志的添加呢?我们有两种方式来实现Spring中AOP的配置。

    通过XML和Annotation配置AOP

    Annotation
    既然是面向切面编程,首先我们先构造一个切面,我们把什么切进去呢?就是我们的业务逻辑-日志服务。我们希望在添加用户之前收到一条日志。
    需要在XML文件中声明的几条。

        <!--下面这行告诉Spring使用注解配置-->
        <context:annotation-config>
        </context:annotation-config>
        <!--下面这行告诉Spring在main包下自动寻找bean-->
        <context:component-scan base-package="main.*">
        </context:component-scan>
        <!--aspectj的声明-->
        <aop:aspectj-autoproxy/>
    

    下面为切面及切点代码

    /**
     * 基于annotation的AOP配置
     */
    @Component
    @Aspect  // 这是一个切面(aspect)
    public class LogIntercepor {
        // 定义一个切点(PointCut)
        @Pointcut("execution(public void main.dao.UserDaoImpl.save(main.model.User))")
        public void my(){}
    
        // 通知(advice)
        @Before("my()")
        public void before() {
            System.out.println("Method before~");
        }
    
        @AfterReturning("my()")
        public void after() {
            System.out.println("Method after~");
        }
    }
    

    在上述代码中出现了一些AOP的核心概念,在此列举一下:

    1. 通知(advice)
      定义了切面要完成的工作,就是告诉spring什么时候做什么事。
      在Spring中有五种类型通知:

      • Before
      • After
      • After-returning
      • After-throwing
      • Around
    2. 切点(pointcut)
      在日志服务中就是那个我想加入日志的地方。

    3. 切面(aspect)
      试想,我们把一个切面切进了应用程序中,这个切面就是日志服务。

    4. 引入(IIntroduction)

    5. 织入(weaving )

    XML

    一个切面类

    /**
     * 切面
     */
    public class LogInterceporXML {
    
        public void before() {
            System.out.println("XML add before~");
        }
    }
    

    XML中的配置

    <!--首先需要这么一行支持aspectj的自动代理-->
    <aop:aspectj-autoproxy/>
    <!--声明我们的切面的bean对象-->
    <bean id="interceporXML" class="main.aop.LogInterceporXML"></bean>
    <aop:config>
        <!--声明切点-->
        <aop:pointcut id="add"
                      expression="execution(public void main.service.UserService.add(..))"/>
        <!--声明切面-->
        <aop:aspect
                ref="interceporXML">
        <!--在方法执行之前执行我们的方法-->
            <aop:before method="before" pointcut-ref="add"></aop:before>
        </aop:aspect>
    </aop:config>
    

    相关文章

      网友评论

        本文标题:Spring之AOP

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