【源碼】Spring AOP 11 ProxyFactoryBean ProxyFactory AspectJProxyFactory
- 前言
- ProxyFactoryBean
-
- demo
- ProxyFactory
-
- demo
- AspectJProxyFactory
-
- demo
- 總結
前言
三大代理類

ProxyFactoryBean
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
// ...
@Override
@Nullable
public Object getObject() throws BeansException {
// 初始化 Advisors Chain by interceptor names
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工廠 取出包裝成 SingletonTargetSource 傳回
this.targetSource = freshTargetSource();
// 允許自動檢測接口 && 聲明實作的接口為空 && 非直接代理目标類
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
// 則幫助搜尋目标類的接口,如果還沒有,那就隻能 CGLIB 咯
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// 是否當機
super.setFrozen(this.freezeProxy);
// 建立代理并緩存,實際是由父類 ProxyCreator 委托給代理建立器去建立
this.singletonInstance = getProxy(createAopProxy());
}
// 有則直接傳回
return this.singletonInstance;
}
// 交給 AopProxy 建立
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
// ...
}
因為本身是個 FactoryBean 又實作了 BeanFactoryAware 接口,是以直接通過 interceptorNames 從 bean工廠 擷取 advisor | advice (包裝成 DefaultPointcutAdvisor),最終代理執行個體通過
getObject
方法獲得,本質上是由父類 ProxyCreatorSuport 委托給 代理建立器 建立的
demo
@ComponentScan("com.xsn.spring.aop")
@Configuration
public class AopConfig {
@Bean
public PointcutAdvisor myPointcutAdvisor() {
// 正則比對以 a 結尾的方法
return new RegexpMethodPointcutAdvisor(".*a$",
(AfterReturningAdvice) (r, m, a, t) -> {
System.out.println("be proxied after");
});
}
@Bean
public MethodInterceptor myMethodInterceptor() {
return (MethodInterceptor) (mi) -> {
System.out.println("be proxied before");
return mi.proceed();
};
}
@Bean
public ProxyFactoryBean myProxyFactoryBean(A a) throws ClassNotFoundException {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setProxyInterfaces(new Class[]{A.class});
// 從 bean工廠 中找
proxyFactoryBean.setInterceptorNames("myPointcutAdvisor", "myMethodInterceptor");
// proxyFactoryBean.setTargetName("aService");
// 相比上面的方法注入 target 更“優雅”
proxyFactoryBean.setTarget(a);
return proxyFactoryBean;
}
}
@Service
public class AService implements A {
public void a() {
System.out.println("a");
}
@Override
public void b() {
System.out.println("b");
}
@Override
public void c() {
System.out.println("c");
}
}
@Test
public void test1() {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(AopConfig.class);
A a = (A) ac.getBean("myProxyFactoryBean");
a.a();
a.b();
a.c();
}
結果:
be proxied before
a
be proxied after
be proxied before
b
be proxied before
c
顯然, Spring 建立代理用的并不是這種方式。畢竟不可能給每個對象建立一個 工廠bean
ProxyFactory
public class ProxyFactory extends ProxyCreatorSupport {
// ...
@SuppressWarnings("unchecked")
public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {
return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();
}
@SuppressWarnings("unchecked")
public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {
return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();
}
public static Object getProxy(TargetSource targetSource) {
if (targetSource.getTargetClass() == null) {
throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(targetSource);
proxyFactory.setProxyTargetClass(true);
return proxyFactory.getProxy();
}
}
提供了幾個靜态方法供我們直接使用。實際上,Spring 就是用它為我們自動建立代理對象的
demo
@Service
public class AService implements A {
public void a() {
System.out.println("a");
}
@Override
public void b() {
System.out.println("b");
}
@Override
public void c() {
System.out.println("c");
}
}
@Aspect
//@Component(我們自己解析,是以不需要放進容器)
public class MyAspect {
@Pointcut("execution(* a())")
public void pt() {
}
@After("pt()")
public void after() {
System.out.println("after proxy");
}
}
@Test
public void test2() {
ProxyFactory proxyFactory = new ProxyFactory(new AService());
// 我們使用 MetadataAwareAspectInstanceFactory 去解析自定義的切面執行個體
MetadataAwareAspectInstanceFactory aspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(
new SingletonMetadataAwareAspectInstanceFactory(
new MyAspect(), "myAspect"
)
);
AspectJAdvisorFactory aspectJAdvisorFactory =
new ReflectiveAspectJAdvisorFactory();
// interceptors chain 的第一個必須是 ExposeInvocationInterceptor,将 MethodInvocation 暴露出去
proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
// 用 ReflectiveAspectJAdvisorFactory 擷取切面對應的 advisors
proxyFactory.addAdvisors(aspectJAdvisorFactory.getAdvisors(aspectInstanceFactory));
A a = (A) proxyFactory.getProxy();
a.a();
a.b();
a.c();
}
結果:
a
after proxy
b
c
注意厘清 ReflectiveAspectJAdvisorFactory 和 DefaultAdvisorChainFactory 的差別
前者借助 MetadataAwareAspectInstanceFactory 的 切面中繼資料 資訊,篩選出要解析的方法。将切面方法上的 AspectJ Expression 解析成 AspectJExpressionPointcut ,然後包裝成 InstantiationModelAwarePointcutAdvisorImpl 。同時還提供了 getAdvice 方法,根據 中繼資料資訊 将 通知 包裝成對應的 AbstractAspectJAdvice 傳回。即 Aspect -> Advisors
後者則是從 Advised 擷取 advisors,周遊與 method 比對,對于比對上的 advisor 則将其 advice 借助 DefaultAdvisorAdapterRegister 适配成 interceptors。即 Advisors -> Interceptors
AspectJProxyFactory
這個類就不貼源碼了,提供了
addAspect
的方法,相當于在 ProxyFactory 的基礎上允許我們增加切面,幫我們解析成 Advisors ,正如我們在上一個 demo 中做的一樣
demo
@Service
public class AService implements A {
public void a() {
System.out.println("a");
}
@Override
public void b() {
System.out.println("b");
}
@Override
public void c() {
System.out.println("c");
}
}
@Aspect
//@Component(我們自己解析,是以不需要放進容器)
public class MyAspect {
@Pointcut("execution(* a())")
public void pt() {
}
@After("pt()")
public void after() {
System.out.println("after proxy");
}
}
@Test
public void test3() {
AspectJProxyFactory aspectJProxyFactory =
new AspectJProxyFactory(new AService());
aspectJProxyFactory.addAspect(MyAspect.class);
A a = (A) aspectJProxyFactory.getProxy();
a.a();
a.b();
a.c();
}
結果:
a
after proxy
b
c
總結
本章節總結了三大代理建立類,我們對代理的建立方式已經有了非常全面的了解了。那 Spring AOP 到底使用哪種方式來建立的代理呢?接下來的章節,我們分析 Spring AOP 的原理
上一篇:【源碼】Spring AOP 10 AopProxyFactory AopProxy
下一篇:【源碼】Spring AOP 12 原了解讀一