前言
参考文章: Spring AOP创建代理方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory(JDK Proxy和CGLB)
Spring AOP是大家都非常熟悉的一个概念,在Spring家族体系中扮演着举足轻重的作用。
然后Spring作为一个优秀的框架,提供了多种应用层面上代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory
注意:此处这里指的是Spring提供的应用层得方式,并不是指的底层实现方式。底层实现方式现在只有业界都熟悉的两种:JDK动态代理和CGLIB代理~
一、 ProxyFactory
ProxyFactory和Spring容器没啥关系,可以直接创建代理来使用,但是它只能通过代码硬编码进行编写,一般都是spring自己内部使用
案例
public interface HelloService { void hello();}
public class HelloServiceImpl implements HelloService {
public void hello() {System.out.println("hello");}
}
开始代理
ProxyFactory proxyFactory = new ProxyFactory(new HelloServiceImpl());
// 添加一个Advice,匿名内部类表示
proxyFactory.addAdvice((AfterReturningAdvice)(returnValue, method, args1, target) ->
System.out.println("AfterReturningAdvice method=" + method.getName()));
HelloService proxy = (HelloService) proxyFactory.getProxy();
proxy.hello();
输出
其核心方法是getProxy(),其源码如下
public class ProxyFactory extends ProxyCreatorSupport {
public Object getProxy() {
return createAopProxy().getProxy();
}
}
其核心逻辑是提供父类ProxyCreatorSupport的createAopProxy()方法获取代理工厂,然后通过代理工厂生成代理类
二、ProxyFactoryBean
ProxyFactoryBean将我们的AOP和IOC融合起来,它是个工厂Bean,然后我们可以自定义我们的代理实现逻辑,最终交给Spring容器管理即可
先定义一个前置通知
@Component("logMethodBeforeAdvice")
public class LogMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("this is LogMethodBeforeAdvice");
}
}
代理类
public interface HelloService { void hello();}
@Service //放到容器中
public class HelloServiceImpl implements HelloService {
public void hello() {System.out.println("hello");}
}
然后在配置类里,注册一个代理Bean
@Bean
public ProxyFactoryBean proxyFactoryBean(HelloService helloService) {
ProxyFactoryBean factoryBean = new ProxyFactoryBean();
//从容器中去拿HelloService
factoryBean.setTarget(helloService);
factoryBean.setInterfaces(HelloService.class);
factoryBean.setInterceptorNames("logMethodBeforeAdvice");
return factoryBean;
}
main方法测试
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
HelloService bean = (HelloService) applicationContext.getBean("proxyFactoryBean");
bean.hello();
}
输出:
由此可见,我们的HelloServiceImpl就被成功代理了。下面我们稍微看看它是怎么创建这个代理的,直接来到getObject()方法:
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
public Object getObject() throws BeansException {
//就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。
//this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。
initializeAdvisorChain();
//生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的Bean,所以要对代理对象的生成做一个区分
if (isSingleton()) {
//生成singleton的代理对象,调用的是其父类ProxyCreatorSupport的createAopProxy方法
return getSingletonInstance();
}
else {
// 生成原型的代理对象,调用的是其父类ProxyCreatorSupport的createAopProxy方法
return newPrototypeInstance();
}
}
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
//依赖AOP基础设施告诉我们要代理的接口。
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// 初始化共享单例实例。
super.setFrozen(this.freezeProxy);
//底层还是父类ProxyCreatorSupport的createAopProxy()方法
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
}
三、 AspectJProxyFactory
其实ProxyFactory拥有的功能AspectjProxyFactory都有,它可以使用编程的方式去创建代理
在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并进行一些较为复杂的配置,低版本Spring AOP的配置是被批评最多的地方。Spring听取这方面的批评声音,并下决心彻底改变这一现状。在Spring2.0中,Spring AOP已经焕然一新,你可以使用@AspectJ注解非常容易的定义一个切面,不需要实现任何的接口
AspectJ是目前大家最常用的 起到集成AspectJ和Spring,也就是我们平时长谈的:自动代理模式。它整个代理的过程全部交给Spring内部去完成,无侵入。
我们只需要配置切面、通知、切点表达式就能自动的实现切入的效果,使用起来极其方便,对调用者可以说是非常透明化的。相信这也是为何当下最流行这种方式的原因~
案例
@Aspect
class MyAspect {
@Pointcut("execution(* hello(..))")
private void beforeAdd() {
}
@Before("beforeAdd()")
public void before1() {
System.out.println("-----------before-----------");
}
}
如果我们现在需要创建一个代理对象,其需要绑定的Advisor逻辑跟上面定义的切面类中定义的Advisor类似。则我们可以进行如下编程:
public static void main(String[] args) {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new HelloServiceImpl());
// 注意:此处得MyAspect类上面的@Aspect注解必不可少
proxyFactory.addAspect(MyAspect.class);
//proxyFactory.setProxyTargetClass(true);//是否需要使用CGLIB代理
HelloService proxy = proxyFactory.getProxy();
proxy.hello();
System.out.println(proxy.getClass()); //class com.sun.proxy.$Proxy6
}
输出
-----------before-----------
this is my method~~
class com.sun.proxy.$Proxy6
这里面很有意思的地方在于:我们只是proxyFactory.addAspect(MyAspect.class);,就自动帮我们完成了方法、通知的绑定工作。
原理
public class AspectJProxyFactory extends ProxyCreatorSupport {
/** Cache for singleton aspect instances */
private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<>();
//基于AspectJ时,创建Spring AOP的Advice 下面详说
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
public AspectJProxyFactory() {
}
public AspectJProxyFactory(Object target) {
Assert.notNull(target, "Target object must not be null");
setInterfaces(ClassUtils.getAllInterfaces(target));
setTarget(target);
}
public AspectJProxyFactory(Class<?>... interfaces) {
setInterfaces(interfaces);
}
// 这两个addAspect方法是最重要的:我们可以把一个现有的aspectInstance传进去,当然也可以是一个Class(下面)======
public void addAspect(Object aspectInstance) {
Class<?> aspectClass = aspectInstance.getClass();
String aspectName = aspectClass.getName();
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
// 显然这种直接传实例进来的,默认就是单例的。不是单例我们就报错了~~~~
if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
throw new IllegalArgumentException(
"Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect");
}
// 这个方法就非常的关键了~~~ Singleton...是它MetadataAwareAspectInstanceFactory的子类
addAdvisorsFromAspectInstanceFactory(
new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));
}
public void addAspect(Class<?> aspectClass) {
String aspectName = aspectClass.getName();
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);
addAdvisorsFromAspectInstanceFactory(instanceFactory);
}
// 从切面工厂里,把对应切面实例里面的增强器(通知)都获取到~~~
private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
// 从切面工厂里,先拿到所有的增强器们~~~
List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
Class<?> targetClass = getTargetClass();
Assert.state(targetClass != null, "Unresolvable target class");
advisors = AopUtils.findAdvisorsThatCanApply(advisors, targetClass);
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
AnnotationAwareOrderComparator.sort(advisors);
addAdvisors(advisors);
}
}
注意:
需要注意的是在使用AspectjProxyFactory
基于切面类创建代理对象时,我们指定的切面类上必须包含@Aspect注解。
虽然我们自己通过编程的方式可以通过AspectjProxyFactory
创建基于@Aspect标注的切面类的代理,@EnableAspectJAutoProxy使用基于注解的Aspectj
风格的Aop
时,Spring内部不是通过AspectjProxyFactory
创建的代理对象,而是通过ProxyFactory(这个在分析自动代理源码的时候有说到过~~~~)
总结
这三个类本身没有什么关系,但都继承自:ProxyCreatorSupport,创建代理对象的核心逻辑都是在ProxyCreatorSupport的
createAopProxy
方法中实现的。
AspectJProxyFactory
,ProxyFactoryBean
,ProxyFactory
大体逻辑如下:
1、填充AdvisedSupport
(ProxyCreatorSupport
是其子类)
2、交给父类ProxyCreatorSupport
处理调用createAopProxy
方法得到JDK或者CGLIB的AopProxy
代理对象。
3、调用这个代理对象时,会被invoke或者intercept方法拦截 (在JdkDynamicAopProxy
和CglibAopProxy
中), 并且在这两个方法中调用ProxyCreatorSupport
的getInterceptorsAndDynamicInterceptionAdvice
方法去初始化advice和各个方法直接映射关系并缓存