【JavaEE进阶】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 {
@Override
public void rentHouse() {
System.out.println("我是房东, 我出租房子");
}
@Override
public 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;
}
@Override
public void rentHouse() {
//代理前
System.out.println("我是中介, 开始代理");
//出租房子
target.rentHouse();
//出租后
System.out.println("我是中介, 结束代理");
}
@Override
public 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;
}
@Override
public 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) 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.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;
}
/**
* 调用代理对象
*/
@Override
public 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.
*
* <p>This 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.
*
* <p>Such auto-proxying is particularly useful if there's 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.
*
* <p>Subclasses 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.
*
* <p>Any 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 ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/**
* Convenience constant for subclasses: Return value for "do not proxy".
* @see #getAdvicesAndAdvisorsForBean
*/
@Nullable
protected 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;
@Nullable
private TargetSourceCreator[] customTargetSourceCreators;
@Nullable
private BeanFactory beanFactory;
private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
private final Map<Object, Object> earlyBeanReferences = new ConcurrentHashMap<>(16);
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
/**
* Set whether the proxy should be frozen, preventing advice
* from being added to it once it is created.
* <p>Overridden from the superclass to prevent the proxy configuration
* from being frozen before the proxy is created.
*/
@Override
public void setFrozen(boolean frozen) {
this.freezeProxy = frozen;
}
@Override
public boolean isFrozen() {
return this.freezeProxy;
}
/**
* Specify the {@link AdvisorAdapterRegistry} to use.
* <p>Default 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.
* <p>Note 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.
* <p>If this property isn't 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;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
/**
* Return the owning {@link BeanFactory}.
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
*/
@Nullable
protected BeanFactory getBeanFactory() {
return this.beanFactory;
}
@Override
@Nullable
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
if (this.proxyTypes.isEmpty()) {
return null;
}
Object cacheKey = getCacheKey(beanClass, beanName);
return this.proxyTypes.get(cacheKey);
}
@Override
public 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);
}
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
return null;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyBeanReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
@Nullable
public 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;
}
@Override
public 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
*/
@Override
@Nullable
public 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.
* <p>Note: 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.
* <p>The 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.
* <p>Sometimes 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.
* <p>This 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
*/
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't 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; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's 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 loader
ClassLoader 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.
* <p>Checks 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 bean's target class already, allowing the ClassFilter check
* to be skipped when building advisors chains for AOP invocations.
* <p>Default 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();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
if (specificInterceptors.length > 0) {
// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
allInterceptors.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);
List<Advisor> 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.
* <p>The 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
*/
@Nullable
protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
@Nullable TargetSource customTargetSource) throws BeansException;
}
代理工厂有一个重要的属性: proxyTargetClass,默认值为false.也可以通过程序设置
Spring Boot 2.X开始,默认使用CGLIB代理
可以通过配置项 spring.aop.proxy-target-class=false 来进行修改, 设置默认为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.
* <p>Will 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.
* <p>No 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.
* <p>Convenience 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.
* <p>Can be called repeatedly. Effect will vary if we've added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses 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.
* <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) {
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 facility's 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.
* <p>Convenience 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(Class<T> 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(Class<T> 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.
*
* <p>Creates a CGLIB proxy if one the following is true for a given
* {@link AdvisedSupport} instance:
* <ul>
* <li>the {@code optimize} flag is set
* <li>the {@code proxyTargetClass} flag is set
* <li>no proxy interfaces have been specified
* </ul>
*
* <p>In 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;
@Override
public 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类中:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
return buildProxy(classLoader, false);
}
@Override
public 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 above
ProxyCallbackFilter 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() failed
throw 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动态代理的区别?
总结