Spring - AOP

1. 介绍

AOP就是面向切面编程,简单说就是,在你执行别人的代码中坚插入你想执行的代码,在日常生活中,代理(中介)就是这么一个角色,先看看生活的例子,

在没有代理之前:你现在需要去澳洲旅行,所以你需要买机票,但你不知道那个航空公司比较便宜,甚至那天买会比较便宜,如果你每天都上网查询机票价格,你会觉得很浪费时间,这个时候,你就需要一个代理,帮你完成看机票这么繁琐的事情

有了代理之后:你只需要关注,买完机票之后所做的事情,例如订酒店。买机票这个动作你就交给你的代理去完成就好了

 

根据上面的这个例子,我们这里就可以看看代码的实现了,我们会分3个方式来看

  • 原始JDK实现
  • gclib实现
  • spring实现
    • 半自动
    • 全自动

 

2.最原始的JDK做法

在这个列子中,就是不适用spring实现,这个是一个工厂类,使用者只需要执行这个createUserService的方法,就可以获取UserService的接口,然后执行所需要要的业务

 

工厂类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanFacotry {

    public static UserService createUserService() {
        /**
         * 1. 创建目标对象
         */
        final UserService userService = new UserServiceImpl();
        
        /**
         * 2. 创建切面对象
         */
        final MyAspect myAspect = new MyAspect();
        
        /**
         * 3. 整合目标对象 和 切面对象
         * 所以需要使用JDK的动态代理,创建代理对象
         */
        UserService proxyUserService = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),UserServiceImpl.class.getInterfaces(),new InvocationHandler() {
            
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //执行切面的before方法
                myAspect.beforeInvokeTarget();
                
                Object obj = method.invoke(userService, args);
                
                //执行切面的after方法
                myAspect.afterInvokeTarget();
                
                return obj;
            }
        });
        
        return proxyUserService;
    }
}

 

测试类

import org.junit.Test;

public class TestAOP {

    @Test
    public void test() {
        UserService userService = MyBeanFacotry.createUserService();
        userService.addUser();
    }
}

 

3. 通过cgLib实现

这里需要引用cglib的Jar包,但是spring-core的jar包里面已经引用了,所以这里就不需要引入了,测试类跟2的一样就可以,只需要改动一个工厂类就行

public class MyBeanFacotry {public static UserService createUserService() {
        /**
         * 1. 创建目标对象
         */
        final UserService userService = new UserServiceImpl();
        
        /**
         * 2. 创建切面对象
         */
        final MyAspect myAspect = new MyAspect();
        
        /**
         * 3. 整合目标对象 和 切面对象
         * 这里使用cglib创建代理对象
         */
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(userService.getClass());
        
        enhancer.setCallback(new MethodInterceptor() {
            
            public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
                Object obj = arg1.invoke(userService, arg2);
                return obj;
            }
        });
        UserService proxyUserService = (UserService)enhancer.create();
        
        return proxyUserService;
    }
}

 

4. 接下来就是用apache的AOP

跟上面两个方法不同是,这里只需要配置xml,这里需要使用到aopalliance-x.x.jar包和aspectjweaver-x.x.x.jar

接口和实现类跟上面一样,这里就不重复写了,这里只写2个类和一个配置文件

 

切面类

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAspect implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("切入前");
        
        Object obj = invocation.proceed();
        
        System.out.println("切入后");
        
        return obj;
    }

}

 

配置文件

稍微讲解一下aop:config节点

其中pointcut 是切入点,expression是表达式,id是切入点ID,主要通知引用

advisor是通知,advice-ref就是指向切面类的bean,pointcut-ref就指向切入点的id

<?xml version="1.0" encoding="UTF-8" ?>
<beans   xmlns="http://www.springframework.org/schema/beans" 
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         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/context
                              http://www.springframework.org/schema/context/spring-context.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
        
        
        <bean id="userService" class="com.test.spring.aop.b.UserServiceImpl"></bean>
        
        <bean id="myAspect" class="com.test.spring.aop.b.MyAspect"></bean>
        
        <aop:config>
            <aop:pointcut expression="execution(* com.test.spring.aop.b.UserServiceImpl.deleteUser(..))" id="myCutPoint"/>
            <aop:advisor advice-ref="myAspect" pointcut-ref="myCutPoint"/>
        </aop:config>
     
</beans>

 

测试类

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {

    @Test
    public void test() {
        String configPath = new String("com/test/spring/aop/b/springConfig.xml");
        
        ApplicationContext context = new ClassPathXmlApplicationContext(configPath);
        UserService userService = context.getBean("userService",UserService.class);
        userService.addUser();
    }
}

 

总结,后面的章节将会讲解一下AspectJ

上一篇:springboot测试类注解


下一篇:Spring -bean的装配和注解的使用