Spring AOP是大家都非常熟悉的一个概念,在Spring家族体系中扮演着举足轻重的作用。
然后Spring作为一个优秀的框架,提供了多种应用层面上代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory
而他们都继承于ProxyCreatorSupport。
注意:此处这里指的是Spring提供的应用层得方式,并不是指的底层实现方式。底层实现方式现在只有业界都熟悉的两种:JDK动态代理和CGLIB代理
public class ProxyCreatorSupport extends AdvisedSupport {
//忽略代码....
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//createAopProxy底层是DefaultAopProxyFactory的createAopProxy方法
return getAopProxyFactory().createAopProxy(this);
}
DefaultAopProxyFactory
的createAopProxy
方法
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("...");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
使用Spring提供的类org.springframework.aop.framework.ProxyFactoryBean
是创建AOP的最基本的方式。
它是个工厂Bean,然后我们可以自定义我们的代理实现逻辑,最终交给Spring容器管理即可。
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
/**
* 拦截器列表中某个值的后缀表示要展开全局变量.
*/
public static final String GLOBAL_SUFFIX = "*";
/**
* 需要植入进目标对象的bean列表
* 此处需要注意:这些bean必须实现类 org.aopalliance.intercept.MethodInterceptor
* 或 org.springframework.aop.Advisor的bean ,配置中的顺序对应调用的顺序
*/
private String[] interceptorNames;
@Nullable
private String targetName;
private boolean autodetectInterfaces = true;
private boolean singleton = true;
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
private boolean freezeProxy = false;
@Nullable
private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
private transient boolean classLoaderConfigured = false;
@Nullable
private transient BeanFactory beanFactory;
/** advisor链是否已初始化 */
private boolean advisorChainInitialized = false;
/** 如果这是singleton,则缓存的singleton代理实例。 */
@Nullable
private Object singletonInstance;
//返回对象的实例(可能是共享的或独立的)
public Object getObject() throws BeansException {
//就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。
//this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {logger.info(".....");}
return newPrototypeInstance();
}
}
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//是否已进行过初始化,若以初始化则不再进行初始化
if (this.advisorChainInitialized) {
return;
}
//如果我们配置的interceptorNames不为空
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {throw new IllegalStateException("....."));}
//除非我们使用属性指定了targetSource,否则全局变量不能是最后一个。。。
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException(".....");
}
// 从bean名称具体化拦截器链
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {logger.trace("");}
// 如国拦截器的名称是以*结尾的,说明它要去全局里面都搜索出来
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(".....");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
// 如国拦截器的名称是不以*结尾的
else {
//如果我们到了这里,我们需要添加一个命名的拦截器。
//我们必须检查它是单例还是原型。
Object advice;
//单例
if (this.singleton || this.beanFactory.isSingleton(name)) {
//创建,并把这个Bean把从容器里拿出来
advice = this.beanFactory.getBean(name);
}
//原型
else {
//这是一个原型建议或顾问:用原型替换。
//避免仅仅为了advisor链初始化而不必要地创建原型bean。
advice = new PrototypePlaceholderAdvisor(name);
}
//把bean转换成Advisor,并放在其Advisor链中
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
private void addAdvisorOnChainCreation(Object next, String name) {
//把bean转换成Advisor
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {logger.trace("Adding advisor with name '" + name + "'");}
//将其放在Advisor链中
addAdvisor(advisor);
}
//底层使用DefaultAdvisorAdapterRegistry的wrap方法
private Advisor namedBeanToAdvisor(Object next) {
try {
return this.advisorAdapterRegistry.wrap(next);
}
catch (UnknownAdviceTypeException ex) {
....
}
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
//如果对象是Advisor类型,直接转换
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
//对象必须是Advice类型
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
//把对象转换成Advice类型
Advice advice = (Advice) adviceObject;
//如果是MethodInterceptor类型
if (advice instanceof MethodInterceptor) {
//众所周知,它甚至不需要适配器。
return new DefaultPointcutAdvisor(advice);
}
//如果是Advice类型但不是如果是MethodInterceptor类型类型,需要检查是否支持
for (AdvisorAdapter adapter : this.adapters) {
//检查它是否受支持。
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
案例
@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");
}
}
// 注册一个代理Bean
@Bean
public ProxyFactoryBean proxyFactoryBean(HelloService helloService) {
ProxyFactoryBean factoryBean = new ProxyFactoryBean();
//代理的目标对象 效果同setTargetSource(@Nullable TargetSource targetSource)
// 此处需要注意的是,这里如果直接new,那么该类就不能使用@Autowired之类的注入 因此建议此处还是从容器中去拿
// 因此可以写在入参上(这也是标准的写法~~)
//factoryBean.setTarget(new HelloServiceImpl());
factoryBean.setTarget(helloService);
// setInterfaces和setProxyInterfaces的效果是相同的。设置需要被代理的接口,
// 若没有实现接口,那就会采用cglib去代理
// 需要说明的一点是:这里不设置也能正常被代理(若你没指定,Spring内部会去帮你找到所有的接口,然后全部代理上~~~~~~~~~~~~)
//设置的好处是只代理指定的接口
factoryBean.setInterfaces(HelloService.class);
//factoryBean.setProxyInterfaces(new Class[]{HelloService.class});
// 需要植入进目标对象的bean列表 此处需要注意:
//这些bean必须实现类 org.aopalliance.intercept.MethodInterceptor或
//org.springframework.aop.Advisor的bean ,配置中的顺序对应调用的顺序
factoryBean.setInterceptorNames("logMethodBeforeAdvice");
// 若设置为true,强制使用cglib,默认是false的
//factoryBean.setProxyTargetClass(true);
return factoryBean;
}
// main方法测试:
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
//expected single matching bean but found 2: helloServiceImpl,proxyFactoryBean
// 如果通过类型获取,会找到两个Bean:一个我们自己的实现类、一个ProxyFactoryBean所生产的代理类 而此处我们显然是希望要生成的代理类的 因此我们只能通过名称来(或者加上@Primary)
//HelloService bean = applicationContext.getBean(HelloService.class);
HelloService bean = (HelloService) applicationContext.getBean("proxyFactoryBean");
bean.hello();
System.out.println(bean); //com.fsx.service.HelloServiceImpl@4e50c791
System.out.println(bean.getClass()); //class com.sun.proxy.$Proxy22 用得JDK的动态代理
// 顺便说一句:这样也是没错得。因为Spring AOP代理出来的每个代理对象,都默认实现了这个接口(它是个标记接口)
// 它这个也就类似于所有的JDK代理出来的,都是Proxy的子类是一样的思想~
SpringProxy springProxy = (SpringProxy) bean;
}
public class ProxyFactory extends ProxyCreatorSupport {
//无自己的属性
public ProxyFactory() {
}
public ProxyFactory(Object target) {
setTarget(target);
setInterfaces(ClassUtils.getAllInterfaces(target));
}
public ProxyFactory(Class<?>... proxyInterfaces) {
setInterfaces(proxyInterfaces);
}
public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
addInterface(proxyInterface);
addAdvice(interceptor);
}
public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
addInterface(proxyInterface);
setTargetSource(targetSource);
}
//获取代理对象
public Object getProxy() {
return createAopProxy().getProxy();
}
案例
ProxyFactory proxyFactory = new ProxyFactory(new HelloServiceImpl());
// 添加两个Advise,一个匿名内部类表示
proxyFactory.addAdvice((AfterReturningAdvice)(returnValue, method, args1, target) ->
System.out.println("AfterReturningAdvice method=" + method.getName()));
HelloService proxy = (HelloService) proxyFactory.getProxy();
proxy.hello();
在Spring2.0以前定义一个切面是比较麻烦的,需要实现特定的接口
,并进行一些较为复杂的配置。在Spring2.0后,Spring AOP已经焕然一新,你可以使用@AspectJ注解非常容易的定义一个切面,不需要实现任何的接口,这都是AspectJProxyFactory
的功劳
AspectJ
是目前大家最常用的 起到集成AspectJ和Spring,也就是我们平时长谈的:自动代理模式。它整个代理的过程全部交给Spring内部去完成,无侵入。
我们只需要配置切面、通知、切点表达式就能自动的实现切入的效果,使用起来极其方便,对调用者可以说是非常透明化的。相信这也是为何当下最流行这种方式的原因~
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);
}
}
案例
@Aspect
public class MyAspect {
@Pointcut("execution(* hello(..))")
private void beforeAdd() {
}
@Before("beforeAdd()")
public void before1() {
System.out.println("-----------before-----------");
}
}
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()); //
注意:
需要注意的是在使用AspectjProxyFactory基于切面类创建代理对象时,我们指定的切面类上必须包含@Aspect注解。
虽然我们自己通过编程的方式可以通过AspectjProxyFactory创建基于@Aspect标注的切面类的代理,但是通过配置aop:aspectj-autoproxy/(@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和各个方法直接映射关系并缓存