SpringAOP[4]-代理工厂
序:代理对象的创建
无论是AspecJProxyFactory
、ProxyFactoryBean
、ProxyFactory
大体逻辑都是:
- 填充
ProxyCreatorSupport
,实际上它是Advised
子类,即填充代理配置类(添加Advisor、添加Advice) - 得到JDK或者CGLIB的AopProxy;
- Proxy Bean被调用时,被invoke或intercept方法拦截,并且会调用
ProxyCreatorSupport(AdvisedSupport)
的getInterceptorsAndDynamicInterceptionAdvice
方法去初始化advice和各个方法上的拦截器链并缓存。
上述三个类本身并没有什么关系,但是都继承自ProxyCreatorSupport
,创建代理对象的核心就是在ProxyCreatorSupport
中实现的。
一、通过ProxyFactoryBean配置
FactoryBean目的是构建复杂的Bean对象,而
ProxyFactoryBean
的getObject()
最终产生的便是Proxy Bean。
配置类:
@Configuration public class MyConfig { @Bean public LogMethodBeforeAdvice logMethodBeforeAdvice() { return new LogMethodBeforeAdvice(); } @Bean("tService") public TService tService() { return new TService(); } @Bean("proxyFactoryBean") public ProxyFactoryBean proxyFactoryBean(TService tService) { ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); //代理的目标对象,效果等效于setTargetSource() proxyFactoryBean.setTarget(tService); //设置`String[] interceptorNames`,以便后续初始化"拦截器链"。 proxyFactoryBean.setInterceptorNames("logMethodBeforeAdvice"); return proxyFactoryBean; } }
拦截器类:
public class LogMethodBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("this is logMethodBeforeAdvice!"); } }
目标类:
public class TService { public void run1(){ System.out.println("This is a run1() Method!"); } }
测试类:
public class TestProxy { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); //可以使用@Primary指定元素,或直接使用name名获取。 //Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: // No qualifying bean of type 'com.tellme.Impl.proxy.TService' available: // expected single matching bean but found 2: tService,proxyFactoryBean。(或生成两个Bean名字) //TService bean = applicationContext.getBean(TService.class); //若使用Class获取Bean,会获取到两个Bean对象。 TService bean = (TService)applicationContext.getBean("proxyFactoryBean"); bean.run1(); System.out.println(bean.getClass()); } }
结果:
this is logMethodBeforeAdvice! This is a run1() Method! class com.tellme.Impl.proxy.TService$$EnhancerBySpringCGLIB$$6ac1bfc1
如测试案例所示,构建ProxyFactoryBean
的过程实际上是完成的是代理配置
。即填充Advised
对象。而Advised对象实际上是由多个Advisor
组成。
而ProxyFactoryBean
便是借助于控制反转
,只是传入Interceptors
类名便完成拦截对象的填充。
ProxyFactoryBean实际上实现的是
FactoryBean
接口,那么产生的Bean是getObject
方法返回的。而getObject
便完成代理对象的创建过程。
1.1 初始化AdvisorChain
代理对象的创建,首先要创建配置对象,即实现Advised
接口,Spring实现了该接口。我们最终通过ProxyCreatorSupport
提供的API便可以完成配置
配置Advised
,实际上执行的是initializeAdvisorChain()
。
- 在IOC容器中通过BeanName获取到
Advice
对象,(当然这种情况属于单例
,而Spring作为一个框架,实际上会考虑原型
模式以及通配符
的情况)。 - 借助
AdvisorAdapterRegistry
将Advice
转换为Advisor
(当然pointcut是Pointcut.TRUE
,拦截所有的方法)。 - 将
Advisor
加入到AdvicedSupport
维护的列表中。该代理对象会持有所有的Advisor
。
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware { /** Whether the advisor chain has already been initialized. */ private boolean advisorChainInitialized = false; //(步骤1:获取代理对象) @Override @Nullable public Object getObject() throws BeansException { //初始化AdvisorChain。 initializeAdvisorChain(); if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.info("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } } //(步骤2:初始化过滤器链) private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { //若拦截器链已经初始化,直接跳出。 if (this.advisorChainInitialized) { return; } //该变量实际上是由proxyFactoryBean.setInterceptorNames("logMethodBeforeAdvice");设置的 if (!ObjectUtils.isEmpty(this.interceptorNames)) { if (this.beanFactory == null) { throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); } // Globals can't be last unless we specified a targetSource using the property... if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { throw new AopConfigException("Target required after globals"); } // Materialize interceptor chain from bean names. for (String name : this.interceptorNames) { if (logger.isTraceEnabled()) { logger.trace("Configuring advisor or advice '" + name + "'"); } //若是拦截器名字以*结尾,要全局搜索出来(相当于一个批量处理) //最终依旧会调用addAdvisorOnChainCreation加入到单例池中。 if (name.endsWith(GLOBAL_SUFFIX)) { if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException( "Can only use global advisors or interceptors with a ListableBeanFactory"); } addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } else { // If we get here, we need to add a named interceptor. // We must check if it's a singleton or prototype. Object advice; if (this.singleton || this.beanFactory.isSingleton(name)) { // Add the real Advisor/Advice to the chain. //若是拦截器为单例,那么在单例池中获取单例对象 advice = this.beanFactory.getBean(name); } else { // It's a prototype Advice or Advisor: replace with a prototype. // Avoid unnecessary creation of prototype bean just for advisor chain initialization. //若是多例,每次均产生一个拦截器对象 advice = new PrototypePlaceholderAdvisor(name); } //将获取到的拦截器对象加入到拦截器链中。 addAdvisorOnChainCreation(advice, name); } } } //设置标识为true。 this.advisorChainInitialized = true; } //(步骤3:将advice转转化为Advisor) private void addAdvisorOnChainCreation(Object next, String name) { // We need to convert to an Advisor if necessary so that our source reference // matches what we find from superclass interceptors. Advisor advisor = namedBeanToAdvisor(next); if (logger.isTraceEnabled()) { logger.trace("Adding advisor with name '" + name + "'"); } //将Advisor加入到Advised的配置列表中 addAdvisor(advisor); } //(步骤4:转换为Advisor) private Advisor namedBeanToAdvisor(Object next) { try { return this.advisorAdapterRegistry.wrap(next); } catch (UnknownAdviceTypeException ex) { throw new AopConfigException("Unknown advisor type " + next.getClass() + "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," + "which may also be target or TargetSource", ex); } } }
实际上执行的是wrap()方法
DefaultPointcutAdvisor(advice)
将advice转换为了增强器
即Advisor
。Pointcut使用的是Pointcut.TRUE
,即拦截target
中所有的Method
。public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<>(3); public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } @Override public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); } }
调用addAdvisor(advisor);
是将Advisor加入到AdvisedSupport
维护的List<Advisor>
中。创建出的代理对象会包含Advised
的配置。
2 获取代理对象
源码:org.springframework.aop.framework.ProxyFactoryBean#getObject
public Object getObject() throws BeansException { //初始化AdvisorChain(此时我们在这...) initializeAdvisorChain(); if (isSingleton()) { //返回单例对象。 return getSingletonInstance(); } else { if (this.targetName == null) { logger.info("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } }
private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { //根据设置的targetName,去单例池中获取bean对象 this.targetSource = freshTargetSource(); //这一步是如果你手动没有去设置需要被代理的接口,Spring还是会去帮你找看你有没有实现啥接口,然后全部给你代理上。可见Spring的容错性是很强的 if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. Class<?> targetClass = getTargetClass(); if (targetClass == null) { throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); } //Spring自动寻找接口,并且设置接口 setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // Initialize the shared singleton instance. super.setFrozen(this.freezeProxy); //创建代理对象。 this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; }
//返回代理对象 protected Object getProxy(AopProxy aopProxy) { //实际上是调用的AopProxy对象创建的代理对象。 return aopProxy.getProxy(this.proxyClassLoader); }
1. 2. 脱离IOC容器使用
public class ProxyFactoryBeanDemo { public static void main(String[] args) { String pointcutExpression = "execution (void com.tellme.Impl.proxy.TService.run1())"; ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setTarget(new TService()); //设置切点 AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(pointcutExpression); Advice advice=(MethodInterceptor) invocation -> { System.out.println("请求before..."); Object obj = invocation.proceed(); System.out.println("请求after..."); return obj; }; //创建Advisor Advisor advisor=new DefaultPointcutAdvisor(pointcut,advice); //加入到Advised过滤器链中 proxyFactoryBean.addAdvisor(advisor); //获取代理对象 TService service = (TService)proxyFactoryBean.getObject(); service.run1(); System.out.println(service.toString()); } }
借助IOC容器,实际上做两件事情:
- 初始化
AdvisorChain
,根据传入的proxyFactoryBean.setInterceptorNames("");
去IOC容器中获取Advice
对象。 - 根据
Advised
配置,创建Proxy
对象。
最后都借助于getProxy(createAopProxy())
产生代理对象。所以PoxyFactoryBean
可以不借助于IOC执行。
二、 通过AspectJProxyFactory配置
@Aspect public class MyAspect { @Pointcut("execution (void com.tellme.Impl.proxy.TService.run1())") private void beforeAdd(){ } @Before("beforeAdd()") public void before1(){ System.out.println("---------before----------"); } }
public class Demo { public static void main(String[] args) { AspectJProxyFactory proxyFactory=new AspectJProxyFactory(new TService()); proxyFactory.addAspect(MyAspect.class); TService bean =proxyFactory.getProxy(); bean.run1(); } }
我们传入MyAspect
类,便自动完成了代理。
-
需要注意的是:使用
AspectjProxyFactory
基于切面类创建代理对象时,我们指定的切面类必须包含@Aspect
注解。 -
虽然我们自己可以通过编程的方式可以通过
AspectjProxyFactory
创建基于@Aspect
切面类的代理类,但是通过<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)
使用基于注解的AspectJ
风格的AOP时,Spring内部不是通过AspectjProxyFactory创建的代理对象,而是通过ProxyFactory。