上一章中我们分析了ProxyFactory,它是Spring AOP核心的底层实现。然而硬编码的方式还是过于繁琐且不易使用,本章我们将讨论ProxyFactoryBean,它结合了ProxyFactory和Ioc中的FactoryBean扩展,使得可以通过XML配置的方式来实现Spring AOP。关于Spring AOP创建代理的具体实现本章将不会再赘述,而是主要讨论FactoryBean扩展结合Spring AOP的使用。
1.FactoryBean简介
我在IOC容器(四)-FactoryBean一篇中已详细地介绍了FactoryBean在Spring IOC中的实现原理,这里还是简单介绍一下。
FactoryBean顾名思义,工厂Bean,即可以动态创建Bean的Bean。对于一些只有在运行时才能明确的对象来说,直接在XML中定义已不能满足,而是通过定义一个工厂类,在运行时根据不同配置来生成最终的对象。
FactoryBean是Spring IOC的两大扩展之一(另一个是BeanPostProcessor),由此与Spring集成的功能众多,包括但不限于AOP,ORM,事务管理,Remoting。
简单看下AbstractBeanFactory中对FactoryBean处理的代码
// 单例
if (mbd.isSingleton()) {
// 获取单例的bean对象
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
[@Override](https://my.oschina.net/u/1162528)
public Object getObject() throws BeansException {
try {
// 匿名内部类中创建bean对象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
// 处理FactoryBean扩展
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
可以看到,对象创建完成后会判断是否为FactoryBean的子类,如果是,则会调用getObject方法返回真正的对象。
2.ProxyFactoryBean实现
回到ProxyFactoryBean,先贴出之前例子的配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 原始对象 -->
<bean id="chromeBrowser" class="com.lcifn.spring.aop.bean.ChromeBrowser"/>
<!-- 环绕增强对象 -->
<bean id="browserAroundAdvice" class="com.lcifn.spring.aop.advice.BrowserAroundAdvice"></bean>
<bean id="browserProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 接口 -->
<property name="interfaces" value="com.lcifn.spring.aop.bean.Browser"/>
<!-- 要代理的对象 -->
<property name="target" ref="chromeBrowser"/>
<!-- 拦截器组 -->
<property name="interceptorNames">
<list>
<value>browserAroundAdvice</value>
</list>
</property>
</bean>
</beans>
基本配置就不说了,按照上面FactoryBean的介绍,Spring创建完ProxyFactoryBean对象后,就会调用其getObject方法。
public Object getObject() throws BeansException {
// 初始化Advisor链
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();
}
}
getObject方法就做了两件事,一是初始化Advisor链,二是创建代理对象,不过创建代理对象时区分单例和多例。
初始化Advisor链
简单地说,就是将配置中的interceptorNames转化成Advisor对象。其中又分为名称精确匹配和名称全局匹配两种,精确匹配就不用说了,全局匹配就是以*号结尾的这种。
对于全局匹配这种,就是在BeanFactory中匹配所有Advisor和Interceptor类型的Bean,再用*前的名称前缀去匹配Bean的名称。
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
String[] globalAdvisorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);
String[] globalInterceptorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);
List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length);
Map<Object, String> names = new HashMap<Object, String>(beans.size());
for (String name : globalAdvisorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
for (String name : globalInterceptorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
OrderComparator.sort(beans);
for (Object bean : beans) {
String name = names.get(bean);
if (name.startsWith(prefix)) {
addAdvisorOnChainCreation(bean, name);
}
}
}
而对于精确匹配的更加清晰,直接取BeanFactory中找,而如果ProxyFactoryBean的singleton属性设置为false时,则封装为PrototypePlaceholderAdvisor延迟创建。
// 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);
两种方式最后都通过addAdvisorOnChainCreation来执行添加操作。其中重要的是将根据name从BeanFactory中获得的对象转换成Advisor,因为interceptorNames支持Advisor,Advice,MethodInterceptor多种类型的对象name,通过namedBeanToAdvisor方法统一转成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.
// 转换Bean对象为Advisor
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
}
private Advisor namedBeanToAdvisor(Object next) {
try {
return this.advisorAdapterRegistry.wrap(next);
}
catch (UnknownAdviceTypeException ex) {
// We expected this to be an Advisor or Advice,
// but it wasn't. This is a configuration error.
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);
}
}
这里的advisorAdapterRegistry实现为DefaultAdvisorAdapterRegistry,这个wrap方法也是被多个地方调用以达到统一Advisor,之后方便生成代理拦截器链。
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);
}
创建代理对象
创建代理对象时根据singleton属性决定创建的对象是单例还是多例。我们以单例的来看
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
// 返回targetSource
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;
}
freshTargetSource判断targetName为null,直接返回targetSource,否则从beanFactory根据targetName获取target对象。
对于代理接口集合为空,且proxyTargetClass为空时,从targetClass获取其实现的接口集合作为代理接口。因而在配置ProxyFactoryBean时,可以不用指定interfaces属性。
getProxy方法的实现同ProxyFactory一致,都是通过AopProxyFactory->AopProxy->Proxy的方式,具体可见ProxyFactory中的创建代理一节。返回的对象赋予类变量作为单例缓存。
对于多例的情况,调用的newPrototypeInstance方法
private synchronized Object newPrototypeInstance() {
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// The copy needs a fresh advisor chain, and a fresh TargetSource.
TargetSource targetSource = freshTargetSource();
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
copy.setInterfaces(
ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
}
copy.setFrozen(this.freezeProxy);
if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
return getProxy(copy.createAopProxy());
}
通过创建一个新的基类对象ProxyCreatorSupport,并copy所有配置的方式每次生成一个新的对象,最后通过getProxy方法获取代理对象。
至此ProxyFactoryBean的介绍就结束了,它主要的特点就是使用FactoryBean同IOC进行了结合。大家都知道Spring框架是一种微内核的设计,包括其AOP,事务管理等许多功能都是通过扩展的方式来设计的。而这种设计思想随着深入到各功能源码,包括一些其他框架同Spring的整合,不能不说这是Spring生态繁荣的一个重要原因