Spring AOP在FactoryBean中使用 spring

前面说到ProxyFactory是将SpringAOP中几个元素整合起来的功臣,但是我们看看他所继承的ProxyCreatorSupport主要有三个具体的分支,用来在不同的场景:

根据名字可以看出另外两个
1、ProxyFactoryBean容器中的织入器
2、AspectJProxyFactory对AspectJ的支持,编程式或注解

ProxyFactoryBean

对SpringAOP的使用,更多的时候是结合Spring容器来发挥他的优势。而这一点,我们之前介绍的ProxyFactory更多偏向于编程式的实现。而与容器的整合这就是ProxyFactoryBean所做的事情。

首先他继承了FactoryBean,那么就有了作为容器的特性。我们知道FactoryBean有一个很重要的方法来注入实现类叫

T getObject() throws Exception;

我们来看看具体的实现方法

public Object getObject() throws BeansException {
	initializeAdvisorChain();
	if (isSingleton()) {
		return getSingletonInstance();
	}
	else {
		if (this.targetName == null) {
			logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
					"Enable prototype proxies by setting the 'targetName' property.");
		}
		return newPrototypeInstance();
	}
}

这里对singleton属性是否设置为true来进行分开的处理,如果为true会通过内部的singletonInstance进行缓存:

private synchronized Object getSingletonInstance() {
	if (this.singletonInstance == null) {
		this.targetSource = freshTargetSource();
		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");
			}
			setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
		}
		// Initialize the shared singleton instance.
		super.setFrozen(this.freezeProxy);
		this.singletonInstance = getProxy(createAopProxy());
	}
	return this.singletonInstance;
}

而这里方法getProxy为实际获取代理对象,这个应该和之前ProxyFactory的实现类似:

protected Object getProxy(AopProxy aopProxy) {
	return aopProxy.getProxy(this.proxyClassLoader);
}

而如果为false则每次都新建实例,具体见方法newPrototypeInstance起底层仍然使用了上面的getProxy方法

接下来看看具体的使用,按照之前我们编程式的方法,应该需要注入advisor、interface等
1、interceptorNames指定植入的advisor
2、proxyInterfaces如果是基于接口的代理,通过这个列表类型设置。另外如果没有指定有autodetectInterfaces来自动检测接口,默认为true
3、target设置目标target,封装为SingletonTargetSource对象
4、proxyTargetClass设置是否强制代理class,默认问false。如果为true依赖cglib代理

下面是一个对目标类为class的进行代理了

<bean id="simpleBean" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="target">
		<bean class="org.java.codelib.spring.aop.pointcut.SimpleBean" />
	</property>
	<property name="interceptorNames">
		<list>
			<idref bean="methodMatchPintcut" />
		</list>
	</property>
	<property name="proxyTargetClass" value="true" />
</bean>

<bean id="methodMatchPintcut"
	class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
	<property name="advice" ref="simpleBeanAdvisor" />
	<property name="mappedName" value="sayHi" />
</bean>

<bean id="simpleBeanAdvisor" class="org.java.codelib.spring.aop.pointcut.SimpleAdvice" />

但是这样配置是不是很繁琐,如果有多个需要代理的target该如何办?按照我们一贯的想法一般该有支持正则或是模糊匹配。是的,这个时候就需要自动化代理 >自动化代理的实现是基于BeanPostProcessor的概念之上,在IOC容器注册完Bean后,通过扫描bean来干预其实例化

主要的自动代理的实现类有BeanNameAutoProxyCreatorDefaultAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator

1、BeanNameAutoProxyCreator

<bean id="simpleBean" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
	<property name="beanNames">
		<bean class="xxx.SimpleBean1" />
		<bean class="xxx.SimpleBean2" />
	</property>
	<property name="interceptorNames">
		<list>
			<idref bean="methodMatchPintcut" />
		</list>
	</property>
</bean>

其中beanNames也可以更简洁的使用*通配

	<property name="beanNames">
		<value>simple*,*Service,target*</value>
	</property>

2、DefaultAdvisorAutoProxyCreator 这个属于全自动代理的范畴了,只需要在IOC容器中注册就会自动代理

AspectJAwareAdvisorAutoProxyCreator

这个需要详细讲解,根据名字就可以推断是对AspectJ的自动代理。更多时候我们使用它的一个子类AnnotationAwareAspectJAutoProxyCreator来完成我们需要的工作。关于AspectJ和SpringAOP后面做详细的介绍。我们前面说了ProxyFactory和容器的ProxyFactoryBean。同样,这里也有AspectJProxyFactory来编程式的支持,用起来是这样的:

AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
proxyFactory.setProxyTargetClass(true);
proxyFactory.setTarget(new SimpleBean());
proxyFactory.addAspect(LoggingAnnoAspect.class);
SimpleBean proxyBean = (SimpleBean) proxyFactory.getProxy();
proxyBean.sayHi("Robin");
proxyBean.sayHi();
proxyBean.greet();

或者基于AnnotationAwareAspectJAutoProxyCreator的自动代理,配置文件如下

<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="simpleBean" class="org.java.codelib.spring.aop.pointcut.SimpleBean" />

<bean id="logAspect"
	class="org.java.codelib.spring.aop.pointcut.aspectj.LoggingAnnoAspect" />

更多内容见这里,接下来我们先介绍AspectJ,回头再具体介绍AnnotationAwareAspectJAutoProxyCreator的用法



blog comments powered by Disqus