老客户网站建设,网站建设数据库搭建,青海企业网站制作,文件乱码了怎么恢复在之前的博客中 【JavaEE进阶】Spring AOP使用篇_aop多个切点-CSDN博客
我们主要学习了SpringAOP的应用, 接下来我们来学习SpringAOP的原理, 也就是Spring是如何实现AOP的.
SpringAOP 是基于动态代理来实现AOP的,咱们学习内容主要分以下两部分 1.代理模式 2.Spring AOP源码剖…
在之前的博客中 【JavaEE进阶】Spring AOP使用篇_aop多个切点-CSDN博客
我们主要学习了SpringAOP的应用, 接下来我们来学习SpringAOP的原理, 也就是Spring是如何实现AOP的.
SpringAOP 是基于动态代理来实现AOP的,咱们学习内容主要分以下两部分 1.代理模式 2.Spring AOP源码剖析
1.代理模式
定义: 为其他对象提供一种代理以控制对这个对象的访问, 它的作用就是通过提供一个代理类, 让我们在调用目标方法的时候, 不再是直接对目标方法进行调用, 而是通过代理类间接调用.
在某些情况下, 一个对象不适合或者不能直接引用另一个对象, 而代理对象可以在客户端和目标对象之间起到中介的作用.
使用代理前: 使用代码后: 比如房屋租赁: Subject: 就是提前定义了房东做的事情,交给中介代理,也是中介要做的事情 RealSubiect: 房东 Proxy: 中介 UML 类图如下: 代理模式可以在不修改被代理对象的基础上, 通过扩展代理类, 进行一些功能的附加与增强 根据代理的创建时期, 代理模式分为静态代理和动态代理:
静态代理: 由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 class 文件就已经存在了
动态代理: 在程序运行时,运用反射机制动态创建而成 静态代理: 由程序员创建代理类或特定工具自动生成源代码再对其编译, 在程序运行前代理类的.class 文件就已经存在了动态代理: 在程序运行时, 运用反射机制动态创建而成 以房东和中介的的关系举例: 1.1 静态代理
以房东和中介的例子模拟静态代理:
1.定义接口(定义房东要做的事情,也是中介需要做的事情)
package com.example.aop.proxy;/*** 业务接口类*/
public interface HouseSubject {void rentHouse();void saleHouse();
}2.实现接口(房东出租房子)目标对象:
package com.example.aop.proxy;/*** 业务实现类*/
public class RealHouseSubject implements HouseSubject {Overridepublic void rentHouse() {System.out.println(我是房东, 我出租房子);}Overridepublic void saleHouse() {System.out.println(我是房东, 我出售房子);}
}3.代理(中介,帮房东出租房子)
package com.example.aop.proxy;/*** 静态代理的代理类 (中介)*/public class HouseProxy implements HouseSubject {//房东对象private HouseSubject target;public HouseProxy(HouseSubject target) {this.target target;}Overridepublic void rentHouse() {//代理前System.out.println(我是中介, 开始代理);//出租房子target.rentHouse();//出租后System.out.println(我是中介, 结束代理);}Overridepublic void saleHouse() {//代理前System.out.println(我是中介, 开始代理);//出售房子target.saleHouse();//出租后System.out.println(我是中介, 结束代理);}
}测试:
package com.example.aop.proxy;public class Main {public static void main(String[] args) {
// 静态代理HouseProxy proxy new HouseProxy(new RealHouseSubject());proxy.rentHouse();proxy.saleHouse();System.out.println();HouseSubject houseSubject new RealHouseSubject();houseSubject.rentHouse();houseSubject.saleHouse();}
}上面这个代理实现方式就是静态代理(仿佛啥也没干).
从上述程序可以看出, 虽然静态代理也完成了对目标对象的代理, 但是由于代码都写死了, 对目标对象的每个方法的增强都是手动完成的非常不灵活. 所以日常开发几乎看不到静态代理的场景.
我们修改接口(Subject)和业务实现类(RealSubject)时, 还需要修改代理类(Proxy).
同样的, 如果有新增接口(Subiect)和业务实现类(RealSubiect), 也需要对每一个业务实现类新增代理类(Proxy). 既然代理的流程是一样的, 有没有一种办法, 让他们通过一个代理类来实现呢?
这就需要用到动态代理技术了
1.2 动态代理
相比于静态代理来说动态代理更加灵活. 我们不需要针对每个目标对象都单独创建一个代理对象, 而是把这个创建代理对象的工作推迟到程序运行时由JVM来实现, 也就是说动态代理在程序运行时, 根据需要动态创建生成
比如房屋中介,我不需要提前预测都有哪些业务, 而是业务来了我再根据情况创建
我们还是先看代码再来理解Java也对动态代理进行了实现, 并给我们提供了一些AP1, 常见的实现方式有两种: 动态代理在我们日常开发中使用的相对较少但是在框架中几乎是必用的一门技术, 学会了动态代理之后, 对于我们理解和学习各种框架的原理也非常有帮助.
JDK动态代理
JDK动态代理实现步骤: 定义JDK动态代理类
实现 InvocationHandler 接口
package com.example.aop.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class JDKInvocationHandler implements InvocationHandler {private Object target; //目标对象public JDKInvocationHandler(Object target) {this.target target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(我是代理, 开始代理);//通过反射, 调用目标对象的方法Object result method.invoke(target, args);System.out.println(我是代理, 结束代理);return result;}
}创建一个代理对象并使用: import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {//JDK动态代理/*** public static Object newProxyInstance(ClassLoader loader,* Class?[] interfaces,* InvocationHandler h) {* loader: 加载我们代理类的classload* interfaces: 要实现的接口* h: 代理要做的事情, 需要实现 InvocationHandler 这个接口*///目标对象RealHouseSubject target new RealHouseSubject();//动态生成代理对象HouseSubject proxy (HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[] {HouseSubject.class},new JDKInvocationHandler(target));proxy.rentHouse();proxy.saleHouse();}
}JDK动态代理只能代理接口, 不能代理类:
运行成功 运行失败
CGLIB动态代理
JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类 有些场景下,我们的业务代码是直接实现的,并没有接口定义,为了解决这个问题,我们可以用 CGLIB 动态代理机制来解决.
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库它允许我们在运行时对字节码进行修改和动态生成. CGLIB 通过继承方式实现代理很多知名的开源框架都使用到了CGLIB.
例如 Spring中的 AOP 模块中: 如果目标对象实现了接口则默认采用 JDK动态代理, 否则采用 CGLIB 动态代理.
CGLIB 动态代理类实现步骤 添加依赖
和JDK动态代理不同, CGLlB(Code Generation Library) 实际是属于一个开源项目如果你要使用它的话需要手动添加相关依赖
dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version
/dependency自定义 MethodInterceptor(方法拦截器) 实现MethodInterceptor接
package com.example.aop.proxy;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGLibMethodInterceptor implements MethodInterceptor {private Object target;public CGLibMethodInterceptor(Object target) {this.target target;}/*** 调用代理对象*/Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(我是中介, 开始代理);Object result method.invoke(target, args);System.out.println(我是中介, 结束代理);return result;}
}创建代理类,并使用
package com.example.aop.proxy;import org.springframework.cglib.proxy.Enhancer;public class Main {public static void main(String[] args) {//使用CGLib完成代理//代理接口, 运行成功HouseSubject target new RealHouseSubject();HouseSubject houseSubject (HouseSubject) Enhancer.create(target.getClass(), new CGLibMethodInterceptor(target));houseSubject.saleHouse();houseSubject.rentHouse();System.out.println();//代理类, 运行成功RealHouseSubject realHouseSubject (RealHouseSubject) Enhancer.create(target.getClass(), new CGLibMethodInterceptor(target));realHouseSubject.saleHouse();realHouseSubject.rentHouse();}
}
CGLIB既可以代理接口, 又可以代理类: 代码简单讲解1. Methodinterceptor
MethodInterceptor 和 JDK动态代理中的 InvocationHandler 类似它只定义了一个方法 intercept(),用于增强目标方法,
public interface MethodInterceptor extends Callback {/*** 参数说明: * o: 被代理的对象 * method: ⽬标⽅法(被拦截的⽅法, 也就是需要增强的⽅法) * objects: ⽅法⼊参 * methodProxy: ⽤于调⽤原始⽅法 */Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable;
}2. Enhancer.create() Enhancer.create()用来生成一个代理对象
public static Object create(Class type, Callback callback) {//...代码省略
}参数说明:
type: 被代理类的类型(类或接口) callback: 自定义方法拦截器 MethodInterceptor JDK动态代理和CGLIB动态代理的区别
JDK 可以代理接口, 不可以代理类
CGLib 既可以代理接口, 又可以代理类
JDK 动态代理是 Java 标准库的一部分不需要额外的依赖。只要使用的是 Java 开发环境就可以直接使用 JDK 动态代理
CGLIB 是一个第三方库需要在项目中添加相应的依赖才能使用。 2. SpringAOP 源码阅读
SpringAOP 主要基于两种方式实现的: JDK及 CGLIB 的方式
生成代理对象的逻辑在父类 AbstractAutoProxyCreator 中 Spring 对于 AOP 的实现基本上都是靠 AnnotationAwareAspectJAutoProxyCreator 去完成 /*** {link org.springframework.beans.factory.config.BeanPostProcessor} implementation* that wraps each eligible bean with an AOP proxy, delegating to specified interceptors* before invoking the bean itself.** pThis class distinguishes between common interceptors: shared for all proxies it* creates, and specific interceptors: unique per bean instance. There need not be any* common interceptors. If there are, they are set using the interceptorNames property.* As with {link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names* in the current factory are used rather than bean references to allow correct handling* of prototype advisors and interceptors: for example, to support stateful mixins.* Any advice type is supported for {link #setInterceptorNames interceptorNames} entries.** pSuch auto-proxying is particularly useful if theres a large number of beans that* need to be wrapped with similar proxies, i.e. delegating to the same interceptors.* Instead of x repetitive proxy definitions for x target beans, you can register* one single such post processor with the bean factory to achieve the same effect.** pSubclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type,* by name, by definition details, etc. They can also return additional interceptors that* should just be applied to the specific bean instance. A simple concrete implementation is* {link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names.** pAny number of {link TargetSourceCreator} implementations can be used to create* a custom target source: for example, to pool prototype objects. Auto-proxying will* occur even if there is no advice, as long as a TargetSourceCreator specifies a custom* {link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,* or if none matches, a {link org.springframework.aop.target.SingletonTargetSource}* will be used by default to wrap the target bean instance.** author Juergen Hoeller* author Rod Johnson* author Rob Harrop* author Sam Brannen* since 13.10.2003* see #setInterceptorNames* see #getAdvicesAndAdvisorsForBean* see BeanNameAutoProxyCreator* see DefaultAdvisorAutoProxyCreator*/
SuppressWarnings(serial)
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {/*** Convenience constant for subclasses: Return value for do not proxy.* see #getAdvicesAndAdvisorsForBean*/Nullableprotected static final Object[] DO_NOT_PROXY null;/*** Convenience constant for subclasses: Return value for* proxy without additional interceptors, just the common ones.* see #getAdvicesAndAdvisorsForBean*/protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS new Object[0];/** Logger available to subclasses. */protected final Log logger LogFactory.getLog(getClass());/** Default is global AdvisorAdapterRegistry. */private AdvisorAdapterRegistry advisorAdapterRegistry GlobalAdvisorAdapterRegistry.getInstance();/*** Indicates whether the proxy should be frozen. Overridden from super* to prevent the configuration from becoming frozen too early.*/private boolean freezeProxy false;/** Default is no common interceptors. */private String[] interceptorNames new String[0];private boolean applyCommonInterceptorsFirst true;Nullableprivate TargetSourceCreator[] customTargetSourceCreators;Nullableprivate BeanFactory beanFactory;private final SetString targetSourcedBeans Collections.newSetFromMap(new ConcurrentHashMap(16));private final MapObject, Object earlyBeanReferences new ConcurrentHashMap(16);private final MapObject, Class? proxyTypes new ConcurrentHashMap(16);private final MapObject, Boolean advisedBeans new ConcurrentHashMap(256);/*** Set whether the proxy should be frozen, preventing advice* from being added to it once it is created.* pOverridden from the superclass to prevent the proxy configuration* from being frozen before the proxy is created.*/Overridepublic void setFrozen(boolean frozen) {this.freezeProxy frozen;}Overridepublic boolean isFrozen() {return this.freezeProxy;}/*** Specify the {link AdvisorAdapterRegistry} to use.* pDefault is the global {link AdvisorAdapterRegistry}.* see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry*/public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {this.advisorAdapterRegistry advisorAdapterRegistry;}/*** Set custom {code TargetSourceCreators} to be applied in this order.* If the list is empty, or they all return null, a {link SingletonTargetSource}* will be created for each bean.* pNote that TargetSourceCreators will kick in even for target beans* where no advices or advisors have been found. If a {code TargetSourceCreator}* returns a {link TargetSource} for a specific bean, that bean will be proxied* in any case.* p{code TargetSourceCreators} can only be invoked if this post processor is used* in a {link BeanFactory} and its {link BeanFactoryAware} callback is triggered.* param targetSourceCreators the list of {code TargetSourceCreators}.* Ordering is significant: The {code TargetSource} returned from the first matching* {code TargetSourceCreator} (that is, the first that returns non-null) will be used.*/public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {this.customTargetSourceCreators targetSourceCreators;}/*** Set the common interceptors. These must be bean names in the current factory.* They can be of any advice or advisor type Spring supports.* pIf this property isnt set, there will be zero common interceptors.* This is perfectly valid, if specific interceptors such as matching* Advisors are all we want.*/public void setInterceptorNames(String... interceptorNames) {this.interceptorNames interceptorNames;}/*** Set whether the common interceptors should be applied before bean-specific ones.* Default is true; else, bean-specific interceptors will get applied first.*/public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) {this.applyCommonInterceptorsFirst applyCommonInterceptorsFirst;}Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory beanFactory;}/*** Return the owning {link BeanFactory}.* May be {code null}, as this post-processor doesnt need to belong to a bean factory.*/Nullableprotected BeanFactory getBeanFactory() {return this.beanFactory;}OverrideNullablepublic Class? predictBeanType(Class? beanClass, String beanName) {if (this.proxyTypes.isEmpty()) {return null;}Object cacheKey getCacheKey(beanClass, beanName);return this.proxyTypes.get(cacheKey);}Overridepublic Class? determineBeanType(Class? beanClass, String beanName) {Object cacheKey getCacheKey(beanClass, beanName);Class? proxyType this.proxyTypes.get(cacheKey);if (proxyType null) {TargetSource targetSource getCustomTargetSource(beanClass, beanName);if (targetSource ! null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}}else {targetSource EmptyTargetSource.forClass(beanClass);}Object[] specificInterceptors getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);if (specificInterceptors ! DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);proxyType createProxyClass(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxyType);}}return (proxyType ! null ? proxyType : beanClass);}OverrideNullablepublic Constructor?[] determineCandidateConstructors(Class? beanClass, String beanName) {return null;}Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);this.earlyBeanReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);}OverrideNullablepublic Object postProcessBeforeInstantiation(Class? beanClass, String beanName) {Object cacheKey getCacheKey(beanClass, beanName);if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// Create proxy here if we have a custom TargetSource.// Suppresses unnecessary default instantiation of the target bean:// The TargetSource will handle target instances in a custom fashion.TargetSource targetSource getCustomTargetSource(beanClass, beanName);if (targetSource ! null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}return null;}Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {return pvs; // skip postProcessPropertyValues}/*** Create a proxy with the configured interceptors if the bean is* identified as one to proxy by the subclass.* see #getAdvicesAndAdvisorsForBean*/OverrideNullablepublic Object postProcessAfterInitialization(Nullable Object bean, String beanName) {if (bean ! null) {Object cacheKey getCacheKey(bean.getClass(), beanName);if (this.earlyBeanReferences.remove(cacheKey) ! bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}/*** Build a cache key for the given bean class and bean name.* pNote: As of 4.2.3, this implementation does not return a concatenated* class/name String anymore but rather the most efficient cache key possible:* a plain bean name, prepended with {link BeanFactory#FACTORY_BEAN_PREFIX}* in case of a {code FactoryBean}; or if no bean name specified, then the* given bean {code Class} as-is.* param beanClass the bean class* param beanName the bean name* return the cache key for the given class and name*/protected Object getCacheKey(Class? beanClass, Nullable String beanName) {if (StringUtils.hasLength(beanName)) {return (FactoryBean.class.isAssignableFrom(beanClass) ?BeanFactory.FACTORY_BEAN_PREFIX beanName : beanName);}else {return beanClass;}}/*** Wrap the given bean if necessary, i.e. if it is eligible for being proxied.* param bean the raw bean instance* param beanName the name of the bean* param cacheKey the cache key for metadata access* return a proxy wrapping the bean, or the raw bean instance as-is*/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;}/*** Return whether the given bean class represents an infrastructure class* that should never be proxied.* pThe default implementation considers Advices, Advisors and* AopInfrastructureBeans as infrastructure classes.* param beanClass the class of the bean* return whether the bean represents an infrastructure class* see org.aopalliance.aop.Advice* see org.springframework.aop.Advisor* see org.springframework.aop.framework.AopInfrastructureBean* see #shouldSkip*/protected boolean isInfrastructureClass(Class? beanClass) {boolean retVal Advice.class.isAssignableFrom(beanClass) ||Pointcut.class.isAssignableFrom(beanClass) ||Advisor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass);if (retVal logger.isTraceEnabled()) {logger.trace(Did not attempt to auto-proxy infrastructure class [ beanClass.getName() ]);}return retVal;}/*** Subclasses should override this method to return {code true} if the* given bean should not be considered for auto-proxying by this post-processor.* pSometimes we need to be able to avoid this happening, e.g. if it will lead to* a circular reference or if the existing target instance needs to be preserved.* This implementation returns {code false} unless the bean name indicates an* original instance according to {code AutowireCapableBeanFactory} conventions.* param beanClass the class of the bean* param beanName the name of the bean* return whether to skip the given bean* see org.springframework.beans.factory.config.AutowireCapableBeanFactory#ORIGINAL_INSTANCE_SUFFIX*/protected boolean shouldSkip(Class? beanClass, String beanName) {return AutoProxyUtils.isOriginalInstance(beanName, beanClass);}/*** Create a target source for bean instances. Uses any TargetSourceCreators if set.* Returns {code null} if no custom TargetSource should be used.* pThis implementation uses the customTargetSourceCreators property.* Subclasses can override this method to use a different mechanism.* param beanClass the class of the bean to create a TargetSource for* param beanName the name of the bean* return a TargetSource for this bean* see #setCustomTargetSourceCreators*/Nullableprotected TargetSource getCustomTargetSource(Class? beanClass, String beanName) {// We cant create fancy target sources for directly registered singletons.if (this.customTargetSourceCreators ! null this.beanFactory ! null this.beanFactory.containsBean(beanName)) {for (TargetSourceCreator tsc : this.customTargetSourceCreators) {TargetSource ts tsc.getTargetSource(beanClass, beanName);if (ts ! null) {// Found a matching TargetSource.if (logger.isTraceEnabled()) {logger.trace(TargetSourceCreator [ tsc ] found custom TargetSource for bean with name beanName );}return ts;}}}// No custom TargetSource found.return null;}/*** 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) {return buildProxy(beanClass, beanName, specificInterceptors, targetSource, false);}private Class? createProxyClass(Class? beanClass, Nullable String beanName,Nullable Object[] specificInterceptors, TargetSource targetSource) {return (Class?) buildProxy(beanClass, beanName, specificInterceptors, targetSource, true);}private Object buildProxy(Class? beanClass, Nullable String beanName,Nullable Object[] specificInterceptors, TargetSource targetSource, boolean classOnly) {if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);}ProxyFactory proxyFactory new ProxyFactory();proxyFactory.copyFrom(this);if (proxyFactory.isProxyTargetClass()) {// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {// Must allow for introductions; cant just set interfaces to the proxys interfaces only.for (Class? ifc : beanClass.getInterfaces()) {proxyFactory.addInterface(ifc);}}}else {// No proxyTargetClass flag enforced, lets apply our default checks...if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}Advisor[] advisors buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader getProxyClassLoader();if (classLoader instanceof SmartClassLoader smartClassLoader classLoader ! beanClass.getClassLoader()) {classLoader smartClassLoader.getOriginalClassLoader();}return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));}/*** Determine whether the given bean should be proxied with its target class rather than its interfaces.* pChecks the {link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE preserveTargetClass attribute}* of the corresponding bean definition.* param beanClass the class of the bean* param beanName the name of the bean* return whether the given bean should be proxied with its target class* see AutoProxyUtils#shouldProxyTargetClass*/protected boolean shouldProxyTargetClass(Class? beanClass, Nullable String beanName) {return (this.beanFactory instanceof ConfigurableListableBeanFactory clbf AutoProxyUtils.shouldProxyTargetClass(clbf, beanName));}/*** Return whether the Advisors returned by the subclass are pre-filtered* to match the beans target class already, allowing the ClassFilter check* to be skipped when building advisors chains for AOP invocations.* pDefault is {code false}. Subclasses may override this if they* will always return pre-filtered Advisors.* return whether the Advisors are pre-filtered* see #getAdvicesAndAdvisorsForBean* see org.springframework.aop.framework.Advised#setPreFiltered*/protected boolean advisorsPreFiltered() {return false;}/*** Determine the advisors for the given bean, including the specific interceptors* as well as the common interceptor, all adapted to the Advisor interface.* 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)* return the list of Advisors for the given bean*/protected Advisor[] buildAdvisors(Nullable String beanName, Nullable Object[] specificInterceptors) {// Handle prototypes correctly...Advisor[] commonInterceptors resolveInterceptorNames();ListObject allInterceptors new ArrayList();if (specificInterceptors ! null) {if (specificInterceptors.length 0) {// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORSallInterceptors.addAll(Arrays.asList(specificInterceptors));}if (commonInterceptors.length 0) {if (this.applyCommonInterceptorsFirst) {allInterceptors.addAll(0, Arrays.asList(commonInterceptors));}else {allInterceptors.addAll(Arrays.asList(commonInterceptors));}}}if (logger.isTraceEnabled()) {int nrOfCommonInterceptors commonInterceptors.length;int nrOfSpecificInterceptors (specificInterceptors ! null ? specificInterceptors.length : 0);logger.trace(Creating implicit proxy for bean beanName with nrOfCommonInterceptors common interceptors and nrOfSpecificInterceptors specific interceptors);}Advisor[] advisors new Advisor[allInterceptors.size()];for (int i 0; i allInterceptors.size(); i) {advisors[i] this.advisorAdapterRegistry.wrap(allInterceptors.get(i));}return advisors;}/*** Resolves the specified interceptor names to Advisor objects.* see #setInterceptorNames*/private Advisor[] resolveInterceptorNames() {BeanFactory bf this.beanFactory;ConfigurableBeanFactory cbf (bf instanceof ConfigurableBeanFactory _cbf ? _cbf : null);ListAdvisor advisors new ArrayList();for (String beanName : this.interceptorNames) {if (cbf null || !cbf.isCurrentlyInCreation(beanName)) {Assert.state(bf ! null, BeanFactory required for resolving interceptor names);Object next bf.getBean(beanName);advisors.add(this.advisorAdapterRegistry.wrap(next));}}return advisors.toArray(new Advisor[0]);}/*** Subclasses may choose to implement this: for example,* to change the interfaces exposed.* pThe default implementation is empty.* param proxyFactory a ProxyFactory that is already configured with* TargetSource and interfaces and will be used to create the proxy* immediately after this method returns*/protected void customizeProxyFactory(ProxyFactory proxyFactory) {}/*** Return whether the given bean is to be proxied, what additional* advices (e.g. AOP Alliance interceptors) and advisors to apply.* param beanClass the class of the bean to advise* param beanName the name of the bean* param customTargetSource the TargetSource returned by the* {link #getCustomTargetSource} method: may be ignored.* Will be {code null} if no custom target source is in use.* return an array of additional interceptors for the particular bean;* or an empty array if no additional interceptors but just the common ones;* or {code null} if no proxy at all, not even with the common interceptors.* See constants DO_NOT_PROXY and PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS.* throws BeansException in case of errors* see #DO_NOT_PROXY* see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS*/Nullableprotected abstract Object[] getAdvicesAndAdvisorsForBean(Class? beanClass, String beanName,Nullable TargetSource customTargetSource) throws BeansException;}代理工厂有一个重要的属性: proxyTargetClass,默认值为false.也可以通过程序设置 Spring Boot 2.X开始,默认使用CGLIB代理
可以通过配置项 spring.aop.proxy-target-classfalse 来进行修改, 设置默认为jdk代理 SpringBoot设置 EnableAspectJAutoProxy 无效, 因为Spring Boot 默认使用 AopAutoConfiguration 进行装配
我看点进去看代理⼯⼚的代码 /*** Factory for AOP proxies for programmatic use, rather than via declarative* setup in a bean factory. This class provides a simple way of obtaining* and configuring AOP proxy instances in custom user code.** author Rod Johnson* author Juergen Hoeller* author Rob Harrop* since 14.03.2003*/
SuppressWarnings(serial)
public class ProxyFactory extends ProxyCreatorSupport {/*** Create a new ProxyFactory.*/public ProxyFactory() {}/*** Create a new ProxyFactory.* pWill proxy all interfaces that the given target implements.* param target the target object to be proxied*/public ProxyFactory(Object target) {setTarget(target);setInterfaces(ClassUtils.getAllInterfaces(target));}/*** Create a new ProxyFactory.* pNo target, only interfaces. Must add interceptors.* param proxyInterfaces the interfaces that the proxy should implement*/public ProxyFactory(Class?... proxyInterfaces) {setInterfaces(proxyInterfaces);}/*** Create a new ProxyFactory for the given interface and interceptor.* pConvenience method for creating a proxy for a single interceptor,* assuming that the interceptor handles all calls itself rather than* delegating to a target, like in the case of remoting proxies.* param proxyInterface the interface that the proxy should implement* param interceptor the interceptor that the proxy should invoke*/public ProxyFactory(Class? proxyInterface, Interceptor interceptor) {addInterface(proxyInterface);addAdvice(interceptor);}/*** Create a ProxyFactory for the specified {code TargetSource},* making the proxy implement the specified interface.* param proxyInterface the interface that the proxy should implement* param targetSource the TargetSource that the proxy should invoke*/public ProxyFactory(Class? proxyInterface, TargetSource targetSource) {addInterface(proxyInterface);setTargetSource(targetSource);}/*** Create a new proxy according to the settings in this factory.* pCan be called repeatedly. Effect will vary if weve added* or removed interfaces. Can add and remove interceptors.* pUses a default class loader: Usually, the thread context class loader* (if necessary for proxy creation).* return the proxy object*/public Object getProxy() {return createAopProxy().getProxy();}/*** Create a new proxy according to the settings in this factory.* pCan be called repeatedly. Effect will vary if weve added* or removed interfaces. Can add and remove interceptors.* pUses 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 facilitys default)* return the proxy object*/public Object getProxy(Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}/*** Determine the proxy class according to the settings in this factory.* param classLoader the class loader to create the proxy class with* (or {code null} for the low-level proxy facilitys default)* return the proxy class* since 6.0*/public Class? getProxyClass(Nullable ClassLoader classLoader) {return createAopProxy().getProxyClass(classLoader);}/*** Create a new proxy for the given interface and interceptor.* pConvenience method for creating a proxy for a single interceptor,* assuming that the interceptor handles all calls itself rather than* delegating to a target, like in the case of remoting proxies.* param proxyInterface the interface that the proxy should implement* param interceptor the interceptor that the proxy should invoke* return the proxy object* see #ProxyFactory(Class, org.aopalliance.intercept.Interceptor)*/SuppressWarnings(unchecked)public static T T getProxy(ClassT proxyInterface, Interceptor interceptor) {return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();}/*** Create a proxy for the specified {code TargetSource},* implementing the specified interface.* param proxyInterface the interface that the proxy should implement* param targetSource the TargetSource that the proxy should invoke* return the proxy object* see #ProxyFactory(Class, org.springframework.aop.TargetSource)*/SuppressWarnings(unchecked)public static T T getProxy(ClassT proxyInterface, TargetSource targetSource) {return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();}/*** Create a proxy for the specified {code TargetSource} that extends* the target class of the {code TargetSource}.* param targetSource the TargetSource that the proxy should invoke* return the proxy object*/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();}}createAopProxy的实现在 DefaultAopProxyFactory中 /*** Default {link AopProxyFactory} implementation, creating either a CGLIB proxy* or a JDK dynamic proxy.** pCreates a CGLIB proxy if one the following is true for a given* {link AdvisedSupport} instance:* ul* lithe {code optimize} flag is set* lithe {code proxyTargetClass} flag is set* lino proxy interfaces have been specified* /ul** pIn general, specify {code proxyTargetClass} to enforce a CGLIB proxy,* or specify one or more interfaces to use a JDK dynamic proxy.** author Rod Johnson* author Juergen Hoeller* author Sebastien Deleuze* author Sam Brannen* since 12.03.2004* see AdvisedSupport#setOptimize* see AdvisedSupport#setProxyTargetClass* see AdvisedSupport#setInterfaces*/
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {/*** Singleton instance of this class.* since 6.0.10*/public static final DefaultAopProxyFactory INSTANCE new DefaultAopProxyFactory();private static final long serialVersionUID 7930414337282325166L;Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {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) || ClassUtils.isLambdaClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}/*** Determine whether the supplied {link AdvisedSupport} has only the* {link org.springframework.aop.SpringProxy} interface specified* (or no proxy interfaces specified at all).*/private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {Class?[] ifcs config.getProxiedInterfaces();return (ifcs.length 0 || (ifcs.length 1 SpringProxy.class.isAssignableFrom(ifcs[0])));}}接下来就是创建代理了 JDK动态代理 CGLIB动态代理
CglibAopProxy类中:
Overridepublic Object getProxy(Nullable ClassLoader classLoader) {return buildProxy(classLoader, false);}Overridepublic Class? getProxyClass(Nullable ClassLoader classLoader) {return (Class?) buildProxy(classLoader, true);}private Object buildProxy(Nullable ClassLoader classLoader, boolean classOnly) {if (logger.isTraceEnabled()) {logger.trace(Creating CGLIB proxy: this.advised.getTargetSource());}try {Class? rootClass this.advised.getTargetClass();Assert.state(rootClass ! null, Target class must be available for creating a CGLIB proxy);Class? proxySuperClass rootClass;if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {proxySuperClass rootClass.getSuperclass();Class?[] additionalInterfaces rootClass.getInterfaces();for (Class? additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// Validate the class, writing log messages as necessary.validateClassIfNecessary(proxySuperClass, classLoader);// Configure CGLIB Enhancer...Enhancer enhancer createEnhancer();if (classLoader ! null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader smartClassLoader smartClassLoader.isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setAttemptLoad(true);enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));Callback[] callbacks getCallbacks(rootClass);Class?[] types new Class?[callbacks.length];for (int x 0; x types.length; x) {types[x] callbacks[x].getClass();}// fixedInterceptorMap only populated at this point, after getCallbacks call aboveProxyCallbackFilter filter new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset);enhancer.setCallbackFilter(filter);enhancer.setCallbackTypes(types);// Generate the proxy class and create a proxy instance.// ProxyCallbackFilter has method introspection capability with Advisor access.try {return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks));}finally {// Reduce ProxyCallbackFilter to key-only state for its class cache role// in the CGLIB$CALLBACK_FILTER field, not leaking any Advisor state...filter.advised.reduceToAdvisorKey();}}catch (CodeGenerationException | IllegalArgumentException ex) {throw new AopConfigException(Could not generate CGLIB subclass of this.advised.getTargetClass() : Common causes of this problem include using a final class or a non-visible class,ex);}catch (Throwable ex) {// TargetSource.getTarget() failedthrow new AopConfigException(Unexpected AOP exception, ex);}}
回顾:
1.什么是AOP
2.SpringAOP 的实现方式有哪些?
3.SpringAOP 的实现原理 (基于动态代理 1.JDK 2.CGLib)
4. Spring 使用的是那种代理方式? Spring 默认 proxyTargetClass 值为false, 如果实现了接口, 使用JDK代理, 如果是普通类则使用CGLib代理 SpringBoot从2.x之后, proxyTargetClass值为true, 默认是使用CGLib代理 5. JDK动态代理和CGLib动态代理的区别? 总结