@EnableAspectJAutoProxy:

@Import(AspectJAutoProxyRegistrar.class)

实际是创建了一个以org.springframework.aop.config.internalAutoProxyCreator为beanid的实例AnnotationAwareAspectJAutoProxyCreator.class

===== AnnotationAwareAspectJAutoProxyCreator=== 关键是这是个什么东西?怎么创建的,创建后可以做什么事情

extends ProxyProcessorSupport

extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean

implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

创建过程:

AnnotationAwareAspectJAutoProxyCreator创建的时机比一般的单例bean的创建时机早:registerBeanPostProcessors(beanFactory); 一般单实例bean创建需要到finishBeanFactoryInitialization(beanFactory);才会创建。

关于AspectJAwareAdvisorAutoProxyCreator的几点认识

1 AspectJAwareAdvisorAutoProxyCreator是BeanPostProcessor接口的实现类

2 postProcessBeforeInitialization方法与postProcessAfterInitialization方法实现在父类AbstractAutoProxyCreator中

3 postProcessBeforeInitialization方法是一个空实现

4 逻辑代码在postProcessAfterInitialization方法中

其实aop原理就是给指定的bean生成代理对象,在bean初始化前后,方法执行前后做功能的增强。具体bean代理类在什么时候创建的?其实是在bean创建的初始化化之后,即调用postProcessAfterInitialization时,会调用AspectJAwareAdvisorAutoProxyCreator的postProcessBeforeInitialization为Bean生成代理。

1代理对象实例化----判断是否为生成代理

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {

if (bean != null) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

if (!this.earlyProxyReferences.contains(cacheKey)) {

return wrapIfNecessary(bean, beanName, cacheKey);

}

}

return bean;

}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {

return bean;

}

if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {

return bean;

}

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {

this.advisedBeans.put(cacheKey, Boolean.FALSE);

return bean;

}

	// Create proxy if we have advice.
//那些对象需要创建代理对象。不可能所有的对象都创建代理对象。通过这里判断。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
} /**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); //根据候选的advisors,寻找可以使用的advisors
extendAdvisors(eligibleAdvisors);//向候选Advisor链的开头(也就是List.get(0)的位置)添加一个org.springframework.aop.support.DefaultPointcutAdvisor
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

//围绕canApply方法进行判断

public static List findAdvisorsThatCanApply(List candidateAdvisors, Class<?> clazz) {

if (candidateAdvisors.isEmpty()) {

return candidateAdvisors;

}

List eligibleAdvisors = new LinkedList<>();

for (Advisor candidate : candidateAdvisors) {

if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {

eligibleAdvisors.add(candidate);

}

}

boolean hasIntroductions = !eligibleAdvisors.isEmpty();

for (Advisor candidate : candidateAdvisors) {

if (candidate instanceof IntroductionAdvisor) {

// already processed

continue;

}

if (canApply(candidate, clazz, hasIntroductions)) {

eligibleAdvisors.add(candidate);

}

}

return eligibleAdvisors;

}

/**
* Can the given advisor apply at all on the given class?
* <p>This is an important test as it can be used to optimize out a advisor for a class.
* This version also takes into account introductions (for IntroductionAwareMethodMatchers).
* @param advisor the advisor to check
* @param targetClass class we're testing
* @param hasIntroductions whether or not the advisor chain for this bean includes
* any introductions
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}

//第一个参数advisor的实际类型是AspectJPointcutAdvisor,它是PointcutAdvisor的子类,因此执行下面的的方法:

else if (advisor instanceof PointcutAdvisor) {

PointcutAdvisor pca = (PointcutAdvisor) advisor;

return canApply(pca.getPointcut(), targetClass, hasIntroductions);

}

else {

// It doesn't have a pointcut so we assume it applies.

return true;

}

}

这个方法其实就是拿当前Advisor对应的expression做了两层判断:

目标类必须满足expression的匹配规则

目标类中的方法必须满足expression的匹配规则,当然这里方法不是全部需要满足expression的匹配规则,有一个方法满足即可

如果以上两条都满足,那么容器则会判断该满足条件,需要被生成代理对象,具体方式为返回一个数组对象eligibleAdvisors,该数组对象中存储的是对应的Advisor。

代理对象实例化----为生成代理代码上下文梳理

如果判断了可以为对象创建,接下来在AbstractAutoProxyCreater的wrapIfNecessary看看如何创建代理对象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {

return bean;

}

if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {

return bean;

}

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {

this.advisedBeans.put(cacheKey, Boolean.FALSE);

return bean;

}

	// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

/**

* Create an AOP proxy for the given bean.

* @param beanClass the class of the bean

* @param beanName the name of the bean

* @param specificInterceptors the set of interceptors that is

* specific to this bean (may be empty, but not null)

* @param targetSource the TargetSource for the proxy,

* already pre-configured to access the bean

* @return the AOP proxy for the bean

* @see #buildAdvisors

*/

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,

@Nullable Object[] specificInterceptors, TargetSource targetSource) {

	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
} ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) {

//这里判断这个类:如果aop:config这个节点中proxy-target-class="false"或者proxy-target-class不配置,则不使用CGLIB代理。

if (shouldProxyTargetClass(beanClass, beanName)) {

proxyFactory.setProxyTargetClass(true);

}

else {

//如果满足条件会将这里目标对象实现的所有接口的class对象放到proxyFactory里面去。

evaluateProxyInterfaces(beanClass, proxyFactory);

}

}

//往proxyFactory里面设置属性

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

proxyFactory.addAdvisors(advisors);

proxyFactory.setTargetSource(targetSource);

customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
} return proxyFactory.getProxy(getProxyClassLoader());
} /**
* Create a new proxy according to the settings in this factory.
* <p>Can be called repeatedly. Effect will vary if we've added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses the given class loader (if necessary for proxy creation).
* @param classLoader the class loader to create the proxy with
* (or {@code null} for the low-level proxy facility's default)
* @return the proxy object
*/
public Object getProxy(@Nullable ClassLoader classLoader) {

//实现代码就一行,但是却明确告诉我们做了两件事情:

//创建AopProxy接口实现类

//通过AopProxy接口的实现类的getProxy方法获取对应的代理

return createAopProxy().getProxy(classLoader);

}

分2步看:

第一步:createAopProxy

@SuppressWarnings("serial")

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

/**

  • ProxyConfig的isOptimize方法为true,这表示让Spring自己去优化而不是用户指定

    *ProxyConfig的isProxyTargetClass方法为true,这表示配置了proxy-target-class="true"

    *ProxyConfig满足hasNoUserSuppliedProxyInterfaces方法执行结果为true,这表示对象没有实现任何接口或者实现的接口是SpringProxy接口

    **/

    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {

    Class<?> targetClass = config.getTargetClass();

    if (targetClass == null) {

    throw new AopConfigException("TargetSource cannot determine target class: " +

    "Either an interface or a target is required for proxy creation.");

    }

    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {

    return new JdkDynamicAopProxy(config);

    }

    return new ObjenesisCglibAopProxy(config);

    }

    else {

    return new JdkDynamicAopProxy(config);

    }

    }

    如果类没有实现接口或者让spring自己优化,或者用户指定了proxy-target-class="true",这是使用GGLIB方式创建代理对象。

第二步:getProxy

后面就是创建JdkDynamicAopProxy或者是ObjenesisCglibAopProxy的区别了。

分别说一下两种代理方式:

JdkDynamicAopProxy

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

MethodInvocation invocation;

Object oldProxy = null;

boolean setProxyContext = false;

	TargetSource targetSource = this.advised.targetSource;
Object target = null; try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
} // Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null); // Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
} // Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

spring aop 原理学习的更多相关文章

  1. 笔记-spring aop 原理学习2

    InstantiationAwareBeanPostProcessor AnnotationAwareAspectJAutoProxyCreator https://blog.csdn.net/qq_ ...

  2. 面试问烂的 Spring AOP 原理、SpringMVC 过程(求求你别问了)

    Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...

  3. spring AOP的学习

    1.Spring常用的概念 Joinpoint(连接点): 所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法,因为spring只支持方法类型的连接点. Pointcut(切入点): ...

  4. 【spring 注解驱动开发】Spring AOP原理

    尚学堂spring 注解驱动开发学习笔记之 - AOP原理 AOP原理: 1.AOP原理-AOP功能实现 2.AOP原理-@EnableAspectJAutoProxy 3.AOP原理-Annotat ...

  5. spring ioc 原理 spring aop原理

    大家一直都说spring的IOC如何如何的强大,其实我倒觉得不是IOC如何的强大,说白了IOC其实也非常的简单.我们先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对 ...

  6. spring aop原理分析

    持续更新... aop跟java代理模式有关. java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 工厂模式用到java反射. ao ...

  7. Spring AOP原理(续)

    十二.AOP 1. 说出Spring的通知类型有哪些? spring共提供了五种类型的通知: 通知类型 接口 描述 Around 环绕通知 org.aopalliance.intercept.Meth ...

  8. Spring Boot -- Spring AOP原理及简单实现

    一.AOP基本概念 什么是AOP,AOP英语全名就是Aspect oriented programming,字面意思就是面向切面编程.面向切面的编程是对面向对象编程的补充,面向对象的编程核心模块是类, ...

  9. spring aop原理和实现

    一.aop是什么 1.AOP面向方面编程基于IoC,是对OOP的有益补充: 2.AOP利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可 ...

随机推荐

  1. SDUT 3373 数据结构实验之查找一:二叉排序树

    数据结构实验之查找一:二叉排序树 Time Limit: 400MS Memory Limit: 65536KB Submit Statistic Problem Description 对应给定的一 ...

  2. 【IMOOC学习笔记】多种多样的App主界面Tab实现方法(三)

    FragmentPagerAdapter+ViewPager 与之前直接用ViewPager不同的是,数组里面放的不再是View,而是Fraagment; 使用FragmentPagerAdapter ...

  3. javascript 字典类型的使用

    javascript  字典类型的使用 1.使用Array: var arr = new Array(); arr["zs"] = "zhangsan"; ar ...

  4. gRPC官方文档(gRPC基础:C++)

    文章来自gRPC 官方文档中文版 本教程提供了C++程序员如何使用gRPC的指南. 通过学习教程中例子,你可以学会如何: 在一个 .proto 文件内定义服务. 用 protocol buffer 编 ...

  5. vue框架搭建的详细步骤之项目结构(二)

    上一篇中简单的创建了一个脚手架,这篇简单的讲一下脚手架的项目结构:     (1).build/ 此目录包含开发服务器和生产webpack构建的实际配置.通常,您不需要触摸这些文件,除非您要自定义We ...

  6. JS随机数生成算法

    ------------------------------------------ 知乎上边淘到的知识,又学到了~ http://www.zhihu.com/question/22818104 -- ...

  7. P2488 [SDOI2011]工作安排 费用流

    \(\color{#0066ff}{ 题目描述 }\) 你的任务是制定出一个产品的分配方案,使得订单条件被满足,并且所有员工的愤怒值之和最小.由于我们并不想使用Special Judge,也为了使选手 ...

  8. luogu2522 [HAOI2011]Problem b

    luogu2522[HAOI2011]Problem b 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公 ...

  9. poi进行excle操作

    一 excle导出: 所需要jar包 <dependency> <groupId>org.apache.poi</groupId> <artifactId&g ...

  10. centos上安装docker

    一 docker安装: 1 首先需要检查linux内核的版本,docker要求linux内核是在3.10之上的, uname -r 2 更新yum源,注意这步应该是管理员权限,如果当前不是管理员,切换 ...