使用ProxyFactoryBean实现AOP
代理的原始生成办法
以前我在springAOP里写过aspectJ的代理生成逻辑,也看了spring编码方式的代理生成。我们可以来复习一下。
我们整一个接口和实现类:
public interface MyService2 {
void myMethod2();
}
@Service
public class MyServiceImpl2 implements MyService2 {
@Override
public void myMethod2() {
System.out.println("myMethod2 invoked...");
}
}
再整一个拦截器,或者叫Advice
,就是说,切面怎么切的意思。他接受一个JoinPoint
作为参数,在这里就是MethodInvocation
(一次方法调用)。
@Component
public class MyAdvisor2 implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before invoke " + invocation.getMethod().getName());
invocation.proceed();
System.out.println("after invoke " + invocation.getMethod().getName());
return null;
}
}
然后是配置类:
@Configuration
@ComponentScan("com.ocean.spring.aop.useProxyFactory")
public class ConfigOfAop2 {
@Bean("myProxyFactory")
@Lazy
public ProxyFactory proxyFactory(MyService2 myService2,
MyAdvisor2 myAdvisor2) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(myService2);
proxyFactory.addAdvice(myAdvisor2);
return proxyFactory;
}
}
测试类:
public class AopTest2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigOfAop2.class);
ProxyFactory proxyFactory = context.getBean("myProxyFactory", ProxyFactory.class);
MyService2 proxy = (MyService2)proxyFactory.getProxy();
proxy.myMethod2();
}
}
从这个demo中我们已经可以看到spring的aop全貌了:代理的接口,目标对象,如何代理,以及使用代理工厂去生成代理。
使用ProxyFactoryBean实现AOP
我们还能够使用ProxyFactoryBean
去生成代理,这时候就不再是原始的生成方式了,因为这时需要走spring的bean的生命周期。
他首先是个FactoryBean
,那么今后将使用
@Nullable
T getObject() throws Exception;
去获取对象。
然后他是个BeanClassLoaderAware
, BeanFactoryAware
,所以会在这个对象初始化的时候获取到加载spring的类加载器以及spring的BeanFactory
:
他又是个ProxyCreatorSupport
,所以本质上也是个aop的配置类,在创建aop代理的时候一定会将this
传进去。
分析到这里,我们看看新的demo。
同样还是一个被代理的接口和目标方法:
public interface MyService {
void myMethod();
}
@Service("myService")
public class MyServiceImpl implements MyService {
@Override
public void myMethod() {
System.out.println("myMethod invoked...");
}
}
然后是如何代理:
@Component
public class MyAdvisor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before invoke " + invocation.getMethod().getName());
invocation.proceed();
System.out.println("after invoke " + invocation.getMethod().getName());
return null;
}
}
配置类:
@Configuration
@ComponentScan("com.ocean.spring.aop.use_proxyFactoryBean")
public class ConfigOfAop {
@Bean
public ProxyFactoryBean proxyFactoryBean() throws ClassNotFoundException {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setProxyInterfaces(new Class[]{MyService.class});
proxyFactoryBean.setInterceptorNames("myAdvisor");
proxyFactoryBean.setTargetName("myService");
return proxyFactoryBean;
}
}
测试类:
public class AopTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigOfAop.class);
MyService myService = context.getBean("proxyFactoryBean", MyService.class);
myService.myMethod();
}
}
测试结果没什么好说的。这里的关键是:
MyService myService = context.getBean("proxyFactoryBean", MyService.class);
我要获取的是proxyFactoryBean
,但为什么拿到的是MyService
类型的?
我们先不急类型转换,先看看原生的是什么对象:
他是一个MyService
的一个代理对象,因此可以转成MyService
类型。现在我们需要debug看看生成代理的过程。
proxyFactoryBean
对象在spring初始化的时候已经创建了,所以我们能够在ioc容器中取出。
如果不是FactoryBean
的,就直接打回去了。
去获取里面的对象。
终于到了getObject()
了。
从容器中取出拦截器,然后做成一个Advisor
添加到advisor列表中(Advisor
可以看成是Advice
和Pointcut
的联合):
Advisor
链初始化后,就开始要获取代理了。
然后他又去ioc容器获取目标对象给targetSource
赋值。现在终于做好准备(所有的配置都准备好了)去生成代理了。
的确是把this
作为配置类传进去了。
把配置丢给jdk动态代理。
最后生成代理的部分就是jdk的内容了。
debug的问题
idea来debug的时候,出现了大量的toString
方法,而我们其实只有红框里面的三句是要打印的:
这时候我们做个设置即可(关掉红框的选项):