Spring 源码系列
1、Spring 学习之扩展点总结之后置处理器(一)
2、Spring 学习之扩展点总结之后置处理器(二)
3、Spring 学习之扩展点总结之自定义事件(三)
4、Spring 学习之扩展点总结之内置事件(四)
5、Spring 学习之扩展点总结之@Import(五)
6、Spring 学习之AOP总结之基础介绍(六)
7、Spring 学习之AOP总结之实现代理(七)
8、SpringBoot 学习之自动配置基本原理(八)
9、SpringBoot 学习之启动原理(九)
10、ElasticSearch学习随笔之SpringBoot Starter 操作
11、图数据库 Neo4j 学习之SpringBoot整合
12、SpringBoot 学习之常用 Filter / Advice 总结
13、SpringBoot+FastJson 优雅的过滤 Response Body
14、Spring Security + Oauth2 认证授权
文章目录
前言
在 Spring之 AOP 基础篇中介绍了 AOP 的原理,此篇上代码,主要以 JDK 动态代理实现。
一、ProxyFactoryBean 实现代理
打印日志是项目中最基本的也是最常见的操作,比如下单操作,就需要记录日志以便追踪订单,就用一个简单的下单操作并记录日志来模拟。
1.1、创建被代理对象
首先创建一个订单服务接口 OrderService 接口,并且创建具体的实现类 OrderServiceImpl 实现订单接口。
订单接口:
public interface OrderService {
int save(String productName);
}
订单实现类:
@Component
public class OrderServiceImpl implements OrderService{
@Override
public int save(String productName) {
System.out.println("生成订单操作!");
return 1;
}
}
1.2、创建代理对象
这里主要使用 advice 和 interceptor 来实现,创建一个下单操作前打印日志类 LogBeforeAdvice 并且实现 aop 提供的 advice 接口 MethodBeforeAdvice,再创建一个下单操作前后拦截操作的类 LogInterceptor 并且实现 aop 提供的 MethodInterceptor 接口。
advice 代理类:
public class LogBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String methodName = method.getName();
System.out.println("生成订单方法【 " + methodName + " 】的前置操作,入参是【"+ Arrays.asList(args) +"】");
}
}
interceptor 代理类:
public class LogInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(getClass()+"调用方法前");
Object obj = invocation.proceed();
System.out.println(getClass()+"调用方法后");
return obj;
}
}
1.3、获取代理对象
这里就用 Configuration 配置类里面,@Bean 的方式来创建所有的需要的对象并有 Spring IOC 管理。
用 ProxyFactoryBean 来生产代理对象,ProxyFactoryBean 实现了 FactoryBean,就可以用 getObject 方法来生产代理对象了。
@Configuration
public class MainConfig {
/**
* 创建订单对象
*/
@Bean
public OrderService orderService(){
return new OrderServiceImpl();
}
/**
* 创建 Advice 通知对象
*/
@Bean
public LogBeforeAdvice logBeforeAdvice(){
return new LogBeforeAdvice();
}
/**
* 创建 Interceptor 拦截对象
*/
@Bean
public LogInterceptor logInterceptor(){
return new LogInterceptor();
}
/**
* 使用 FactoryBean 的 getObject方法来生产代理对象
*/
@Bean
public ProxyFactoryBean orderServiceProxy(){
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames("logBeforeAdvice", "logInterceptor");
proxyFactoryBean.setTarget(orderService());
return proxyFactoryBean;
}
}
1.4、调用方法
在 main 方法中用 AnnotationConfigApplicationContext 来生产上下文,并且获取到代理对象,进行调用测试。
public class MainStart {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
OrderService orderService = applicationContext.getBean("orderServiceProxy", OrderService.class);
orderService.save("核桃花生牛奶(箱)");
}
}
调用结果:
从调用结果中可以看到,使用了责任链的方式对 Advice 和 Interceptor 进行了调用,这个例子非常简单,就是提供了 被代理对象 和 代理对象,利用 FactoryBean 的 getObject 对象来创建了一个代理对象。
代理模式需要一个接口(也可以没有),需要一个具体的实现类,定义一个代理类用来包装实现类,在使用的时候需要代理类来生成实例。
二、NameMatchMethodPointcutAdvisor 实现代理
2.1、创建代理对象
使用 NameMatchMethodPointcutAdvisor 的方法实现,就是加入了 Advicor 的概念,什么是 Advisor呢?我们可以称它为一个通知者,有它决定谁可以被代理实现,Advisor 内部有一个 Advice,Advice 负责实现方法的包装,而 Advisor 则负责匹配方法。
可以发现,advisor。setMappedNames 方法可以设置多个方法名,可以是不同对象的方法,这样就比上面的方法更加方便灵活的实现多个代理,Advicor更细粒度的控制了方法代理。
在 Configuration 配置类中加入生成 NameMatchMethodPointcutAdvisor 配置。
/**
* 利用方法匹配的方法生产 Advisor
*/
@Bean
public NameMatchMethodPointcutAdvisor methodPointcutAdvisor(){
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setAdvice(logBeforeAdvice());
advisor.setMappedNames("save", "pay");
return advisor;
}
在 Configuration 配置类中用 ProxyFactoryBean 指定 Advicor 生成代理对象。
@Bean
public ProxyFactoryBean orderServiceProxy(){
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames("methodPointcutAdvisor");
proxyFactoryBean.setTarget(orderService());
return proxyFactoryBean;
}
2.2、调用方法
public class MainStart {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
OrderService orderService = applicationContext.getBean("orderServiceProxy", OrderService.class);
orderService.save("核桃花生牛奶(箱)");
orderService.pay(100);
}
}
测试结果:
从测试结果中可以看出,save 方法和 pay 方法都实现代理了。
到这里,Advice、Advisor、Interceptor 三个概念都介绍完了,不过可以发现,这种实现方法并不是特别方便,我们还需要通过 getBean 方法获取到代理对象并且调用,这是特别不方便的,下面来看看 AutoProxy 代理。
三、AutoProxy实现代理
上面的方法都是明显的指定代理类的 Bean,这样就不能灵活的动态生成配置,AutoProxy 强调自动,那么如何自动呢,Spring 会自动的做生成代理这件事情,使用 BeanNameAutoProxyCreator 来实现自动代理。
3.1、BeanNameAutoProxyCreator 创建代理对象
在 Configuration 配置类中加入生成 BeanNameAutoProxyCreator 配置。
@Bean
public BeanNameAutoProxyCreator autoProxyCreator(){
BeanNameAutoProxyCreator autoProxyCreator = new BeanNameAutoProxyCreator();
//设置需要创建代理Bean名称
autoProxyCreator.setBeanNames("order*");
//设置拦截代理对象名称
autoProxyCreator.setInterceptorNames("logInterceptor");
return autoProxyCreator;
}
3.2、代理测试
public class MainStart {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.save("核桃花生牛奶(箱)");
orderService.pay(100);
}
}
测试结果:
测试结果中看,我们不需要关系代理哪些对象,Spring 通过 order* 已经找到了所有可以代理的对象并生成了代理。
3.3、DefaultAdvisorAutoProxyCreator 创建代理对象
上面是用的 BeanNameAutoProxyCreator 制定方法名称(模糊匹配)自己匹配方法来交给 Advice 处理。上面说到,Advisor 包装了 Advice ,Advisor 负责拦截,Advice 负责处理,所以可不可以实现 Advicor 全局拦截找到需要代理的Bean。
不过,在相同的包下面,还有个弟弟 DefaultAdvisorAutoProxyCreator 使用更加方便,它是在 IOC 容器中所有的 Advisor 来匹配方法,Advice 来处理。
1、 在 Configuration 配置类中加入生成 RegexpMethodPointcutAdvisor 配置,利用正则来实现包的扫描找到所有的 Advisor。
@Bean
public RegexpMethodPointcutAdvisor regexpMethodPointcutAdvisor(){
RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
advisor.setAdvice(logInterceptor());
advisor.setPattern("com.self.*");
return advisor;
}
2、配置 DefaultAdvisorAutoProxyCreator 使所有的 Advisor 生效,无须其他配置。
@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator(){
return new DefaultAdvisorAutoProxyCreator();
}
3.4、代理测试
public class MainStart {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.save("核桃花生牛奶(箱)");
orderService.pay(100);
}
}
测试结果:
从测试结果中可以看出,所有的 Advicor 都生效了,并且被拦截生成代理了。
四、总结
AOP 呢,就是动态代理,Spring 中提供了很多生成代理的方法,此篇中从一个简单的代理到方法名匹配代理,再到正则指定包路径生成代理,越来越方便。也就大概知道 Spring 中的 AOP 大概都有哪些实现方式,不过真正的实现思路还是需要去深究 Spring 里面怎么实现的。
敬请期待后面源码研究。