JDK动态代理
Spring默认采取的动态代理机制实现AOP, 简单来说就是在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。动态代理技术包括Java动态代理和CGLIB动态代理,前者基于接口实现,后者基于类实现。Spring默认采取的Java动态代理机制实现AOP。在介绍Spring AOP原理之前先介绍Java动态代理。
Java动态代理:Java的动态代理是基于接口的,代理类和目标类实现相同的接口,这样他们行为保持了一致性,在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效的对委托类的对象的直接访问,可以很好的隐藏和保护委托对象,同时为实施不同的策略预留空间。
Java动态代理机制中有两个重要的接口和类:接口InvocationHandler()和类Proxy(),位于java.lang.reflect包中,这是实现动态代理的核心。
(1)接口InvocationHandler:动态代理类的调用处理程序
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,该接口中仅定义了一个方法:
public Object invoke(Object proxy, Method method, Object[] args)
其中:第一个参数proxy表示执行这个方法的代理对象,method表示目标对象实际需要执行的方法,args表示目标对象实际要执行的方法所需要的参数。
每一个proxy代理实例都要有一个关联的调用处理程序,该调用处理程序都必须实现InvocationHandler接口。所以在实际编程中,需要先定义一个实现了InvocationHandler接口的调用处理器对象,然后将它作为创建代理类实例的参数(见Proxy类的newProxyInstance()方法)。
(2)Proxy:动态代理类
Proxy类就是用来创建一个代理对象的类,最常用的方法是static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)。这个方法的作用就是创建一个代理对象,其中三个参数为:
1、ClassLoader loader:指定当前目标对象使用类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是Java安全模型的一部分。
2、Class[] interfaces:一个interface对象数组,目标对象实现的接口的类型。表示我们要给代理对象提供什么样的接口。如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
3、InvocationHandler h:一个InvocationHandler调用处理程序对象,它必须是实现了InvocationHandler接口的对象,作用就是定义代理对象中需要执行的具体操作。当执行目标对象的方法时,会关联到一个InvocationHandler对象上,从而触发调用处理程序的方法,会把当前执行目标对象的方法作为参数传入,并最终调用h中的invoke()方法。
其实动态代理类可以看做是这样一种类:它是在运行时生成的类,在生成它时你必须提供一组接口给它,然后该类就宣称它实现了这些接口。你当然可以把该类的实例当做这里接口中的任何一个来用。当然,这个动态代理类其实就是一个代理,它不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。在实际使用代理类的时候,我们必须实现InvocationHandler接口。这样目标对象、需要控制的接口和控制方式都可以动态改变,从而实现灵活的动态代理关系。
实现步骤:
1、创建目标类(委托类)的接口
这里定义了两个接口,interface IBusiness1 和interface IBusiness2,各包含一个方法。
public interface IBusiness1 {
public void doSomething1();
public void hello();
}
public interface IBusiness2 {
public void doSomething2();
}
2、创建目标类(委托类)
创建一个目标类Business,实现这两个接口。
public class IBusiness implements IBusiness1,IBusiness2 {
@Override
public void doSomething1() {
System.out.println("IBusiness1...处理逻辑");
}
@Override
public void doSomething2() {
System.out.println("IBusiness2...处理逻辑");
}
}
3、定义一个代理类的调用处理程序。该程序必须实现接口InvocationHandler,且必须实现接口的invoke方法。
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被转发到调用处理程序的invoke方法。
在invoke中可以对方法进行筛选,如下代码所示,最终IBusiness1的hello()方法并没有被匹配到,所以不会被增强。
public class LogInvocationHandler implements InvocationHandler {
//目标对象 target
Object target;
//构造函数给目标函数赋值
LogInvocationHandler(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println("name="+name);
if(name.matches("(.*)doSomething(.*)")){
//在真实的对象执行之前添加自己的操作
System.out.println("invoke方法开始------------");
}
//执行原有逻辑
Object rev = method.invoke(target, args);
if(name.matches("(.*)doSomething(.*)")){
//在真实的对象执行之后添加自己的操作
System.out.println("invoke方法结束------------");
}
return rev;
}
}
4、通过Proxy的静态方法newProxyInstance()创建一个代理对象。
Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。这个方法的作用就是创建一个代理类对象。该方法有三个参数,三个参数具体解释见上述。
public class test {
public static void main(String[] args) {
//要代理的目标对象
IBusiness iBusiness = new IBusiness();
Class<?>[] interfaces = iBusiness.getClass().getInterfaces();
LogInvocationHandler handler = new LogInvocationHandler(iBusiness);
IBusiness1 proxyInstance = (IBusiness1) Proxy.newProxyInstance(iBusiness.getClass().getClassLoader(), interfaces, handler);
proxyInstance.doSomething1();
proxyInstance.hello();
((IBusiness2)proxyInstance).doSomething2();
}
}
5、通过代理对象调用委托类对象的方法。
其实Proxy类只是一个连接桥,把代理(InvocationHandler)与被代理类关联起来,真正处理事情的是InvocaHandler。InvocationHandler接口中的invoke方法在代理类中是动态实现的,当我们通过动态代理调用一个方法的时候,这个方法的调用会被转发到到调用处理程序的invoke方法中。
//使用代理类的实例来调用方法。
proxyInstance.doSomething1();
proxyInstance.hello();
((IBusiness2)proxyInstance).doSomething2();
运行结果:
name=doSomething1
invoke方法开始------------
IBusiness1...处理逻辑
invoke方法结束------------
name=hello
IBusiness1...hello
name=doSomething2
invoke方法开始------------
IBusiness2...处理逻辑
invoke方法结束------------
动态代理的优势就是可以很方便的对目标类的函数进行统一的处理,而不用修改每个目标类的方法。所有被代理执行的方法在调用执行的时候,其方法只是作为参数传入InvocationHandler中的invoke方法,实际是在invoke方法中处理的,这样通过在invoke方法中我们可以对所有被代理的方法进行相同的增强操作。
Spring AOP的实现原理
下面Spring AOP实现流程图:
(一)标签的解析
首先我们来看下AOP常用的两种实现方式,一种是采用声明的方式来实现(基于XML),一种是采用注解的方式来实现(基于AspectJ)。下面举例说明:
方式一:xml方式配置
第一步:创建被加强类
@Repository
public class UserDao {
public void sys() {
System.out.println("userDao.....");
}
}
第二步:创建增强类
public class Project {
public void before1() {
System.out.println("前置通知。。。。。。。。。");
}
//环绕通知
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知前。。。。。");
point.proceed();
System.out.println("环绕通知后。。。。。。");
}
public void after1() {
System.out.println("后置通知。。。。。。。。。");
}
}
第三步:配置切点和切面
<!-- spring bean的配置 -->
<bean id="userDao" class="com.itheima.test2AOP.UserDao"></bean>
<bean id="userService" class="com.itheima.test2AOP.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="project" class="com.itheima.test2AOP.Project"></bean>
<aop:config>
<aop:pointcut expression="execution(* com.itheima.test2AOP.UserDao.*(..))" id="pointcut1"/>
<aop:aspect ref="project">
<aop:before method="before1" pointcut-ref="pointcut1"/>
<aop:after-returning method="after1" pointcut-ref="pointcut1"/>
<aop:around method="around" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
方式二:通过Spring AOP注解实现
第一步:配置spring文件,开启aop注解
<!-- 开启aop的注解 -->
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.itheima.*"></context:component-scan>
第二步:编写增强类
@Component
@Aspect
public class Project2 {
//方式1:
@Before(value="execution(* cn.ytk.dao.UserDao.*(..))")
public void before() {
System.out.println("前置通知。。。。。。");
}
//方式2:先编写切点在将切点加到加强上。
@Pointcut("execution(* cn.ytk.dao.*.*(..))")
public void after() {}
@AfterReturning("after()")
public void after1() {
System.out.println("....后置通知....");
}
}
从示例中看出,XML方式中使用AOP技术的需要做以下几步:
1)开启AOP注解,aop:aspectj-autoproxy/
2)定义切面类,使用@Aspect注解
3)在切面类上加设注解@Component
4)在切面类中定义切点方法,使用@PointCut注解
5)在切面类中定义通知方法,使用@Before、@After、@Around等注解
6)在通知方法的注解中使用切点方法
下面结合Spring AOP的源码对AOP的实现原理一步步进行分析:
声明了自定义的注解,一定会在程序的某个地方注册对应的解析器。aop:aspectj-autoproxy/注解使用AspectJAutoProxyBeanDefinitionParser解析器进行解析。这个对应关系在AopNamespaceHandler(package org.springframework.aop.config)类中指定。
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
接着来看下AspectJAutoProxyBeanDefinitionParser(package org.springframework.aop.config)解析器的代码。它是一个实现了BeanDefinitionParser接口的类,专门用于解析切面自动代理的Bean定义的解析工作,重点在其parse方法。
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注册AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
//对注解中子类的处理
extendBeanDefinition(element, parserContext);
return null;
}
其中调用了AopNamespaceUtils类(处理Spring AOP命名空间的工具类,package org.springframework.aop.config)的registerAspectJAnnotationAutoProxyCreatorIfNecessary函数。我们进入此函数看一下代码逻辑:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//注册或者升级AutoProxyCreator定义beanName为
// org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//对于proxy-target-class以及expose-proxy属性的处理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//注册组件并通知,便于监听器进一步处理,其中BeanDefinition的className
// 为AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
上述代码一共三行代码,每行代码完成一件事情,都是一个完整的逻辑。
第一行代码:BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement));
注册或者升级AnnotatonAwareAspectJAutoProxyCreator。
我们进入AopConfigUtils类(package org.springframework.aop.config)的registerAspectJAnnotationAutoProxyCreatorIfNecessary函数看看:
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
上面这个函数又实际调用了本类中的registerOrEscalateApcAsRequired函数,我们继续查看该函数的实现逻辑:
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//如果已经存在了自动代理创建器且存在的自动代理创建器与现在的不一致,
// 那么需要根据优先级判断到底使用哪个
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
//改变bean最重要的就是改变bean所对应的className属性
apcDefinition.setBeanClassName(cls.getName());
}
}
//如果已经存在自动代理创建器且与将要创建的一致,那么无需再次创建
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
对于Aop的实现,基本都是靠AnnotatonAwareAspectJAutoProxyCreator去完成的,它可以根据@Point注解定义的切点来自动代理相匹配的bean。但是为了配置简便,Spring使用了自定义的配置帮助我们自动注册AnnotatonAwareAspectJAutoProxyCreator。其注册过程就是在上述函数中实现的。上述代码实现了自动注册AnnotatonAwareAspectJAutoProxyCreator类的功能,同时存在优先级问题,如果已经存在了自动代理创建器,而且存在的与现在的不一致,那么需要根据优先级判断到底使用哪个。
第二行代码:useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
处理proxy-target-class和expose-proxy属性,进入该函数:
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
//对应proxy-target-class属性的处理
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//对应expose-proxy属性的处理
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
proxy-target-class和expose-proxy属性解释:
(1)proxy-target-class属性
Spring AOP使用JDK动态代理或者CGLIB来为目标对象创建代理。如果被代理的目标对象至少实现了一个接口,则使用JDK动态代理,所有该目标类型实现的接口都将被代理。如果该目标对象没有实现任何接口,则创建一个CGLIB代理。也可以强制使用CGLIB代理,强制使用CGLIB代理需要将aop:config的proxy-target-class属性设置为true:<aop:config proxy-target-class=”true”>…</aop:config>
当需要使用CGLIB代理和@AspectJ自动代理支持,可以按照下面的方式设置aop:aspectj-autoproxy的proxy-target-class属性:<aop:aspectj-autoproxy proxy-target-class=”true”>。
(2)expose-proxy属性
Spring AOP无法拦截内部方法调用,比如一个接口里面有两个方法:doSomething1()和doSomething2()。然后在方法1中调用了方法2:this.doSomething2()。此处this指向目标对象,因此调用this.doSomething2()将不会执行doSomething2的增强。(也就是切面只会对doSomething1方法进行增强,但是不会对doSomething2进行增强)。
解决方法:this. doSomething2 ()修改为 ((AService) AopContext.currentProxy()).doSomething2 ()。同时修改Spring AOP的配置:<aop:aspectj-autoproxy expose-proxy="true" />
第三行代码:registerComponentIfNecessary(beanDefinition, parserContext);
注册组件并通知,便于监听器进一步处理。
(二)获取增强方法或者增强器
上面通过自定义配置完成了对AnnotatonAwareAspectJAutoProxyCreator(package org.springframework.aop.aspectj.annotation中)的自动注册。
AnnotatonAwareAspectJAutoProxyCreator类:SpringBoot框架中默认支持的方式。spring aop 开启注解方式之后,该类会扫描所有@Aspect()注释的类,生成对应的advisor。
AnnotationAwareAspectJAutoProxyCreator的继承关系如下:
AnnotationAwareAspectJAutoProxyCreator
--AspectJAwareAdvisorAutoProxyCreator
--AbstractAdvisorAutoProxyCreator
--AbstractAutoProxyCreator
-- ProxyProcessorSupport;
SmartInstantiationAwareBeanPostProcessor;
BeanFactoryAware;
其中
ProxyProcessorSupport
--ProxyConfig;
Ordered;
BeanClassLoaderAware;
AopInfrastructureBean;
SmartInstantiationAwareBeanPostProcessor
--InstantiationAwareBeanPostProcessor
--BeanPostProcessor
BeanFactoryAware
--Aware
AnnotatonAwareAspectJAutoProxyCreator间接实现了BeanPostProcessor接口,所以当Spring加载这个Bean的时候会在实例化之前调用postProcessAfterInitialization这个方法。一直往父类寻找,在其父类AbstractAutoProxyCreator(package org.springframework.aop.framework.autoproxy)实现了该方法。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//根据给定的bean的class和name构建出key,格式:beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//一个非常核心的方法:wrapIfNecessary(),如果它适合被代理,则需要封装指定的bean。
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
其有一个非常核心的方法:wrapIfNecessary()。继续进入该类中的wrapIfNecessary方法实现逻辑:
/**
* 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;
}
//这个bean无需增强
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//判断给定的bean是否是一个基础设施类,基础设施类不应代理,或者配置了指定bean不需要代理。
//所谓InfrastructureClass就是指Advice/PointCut/Advisor等接口的实现类。
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果存在增强方法则创建代理
//获取这个bean的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;
}
从上述代码中我们看到了代理创建的雏形。创建代理主要包含了两个步骤:1、获取增强方法或者增强器。2、根据获取的增强进行代理。
下面我们先来看下获取增强方法或者增强器:
AbstractAutoProxyCreator类的wrapIfNecessary方法中调用了getAdvicesAndAdvisorsForBean,AbstractAutoProxyCreator类只对该方法进行定义,真正实现在其子类AbstractAdvisorAutoProxyCreator(package org.springframework.aop.framework.autoproxy)中实现。
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
上面方法实现又调用了该类中的findEligibleAdvisors方法,进入其代码:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
里面有两个函数findCandidateAdvisors和findAdvisorsThatCanApply。这两个方法就是来获取所有的增强以及寻找增强中适用于bean的增强并应用。
(1) findCandidateAdvisors方法(获取所有的增强)
我们首先进入findCandidateAdvisors看下:
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
方法中调用了BeanFactoryAdvisorRetrievalHelper类(package org.springframework.aop.framework.autoproxy中)的findAdvisorBeans方法(AbstractAdvisorAutoProxyCreator类中声明了advisorRetrievalHelper是BeanFactoryAdvisorRetrievalHelper类型。private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;)。
BeanFactoryAdvisorRetrievalHelper这个类是一个Spring AOP内部工具类,用来从bean容器中获取所有Spring的Advisor bean(这里的 Spring Advisor bean指的是实现了接口org.springframework.aop.Advisor的bean)。是真正去容器中找出所有的Advisor的类。该工具内部使用了缓存机制,虽然公开的查找方法可能会被调用多次,但并不是每次都会真正查找,而是会利用缓存。
public List<Advisor> findAdvisorBeans() {
//cachedAdvisorBeanNames是advisor名称的缓存
String[] advisorNames = this.cachedAdvisorBeanNames;
//如果cachedAdvisorBeanNames为空,则到容器中查找,并设置缓存,后续直接使用缓存即可
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
//从容器中查找Advisor类型的bean的名称
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
//遍历advisorNames
for (String name : advisorNames) {
if (isEligibleBean(name)) {
//忽略郑州创建中的advisor bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
//调用getBean方法从容器中获取名称为name的bean,并将bean添加到advisors中
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
(2)findAdvisorsThatCanApply方法(寻找增强中适用于bean的增强并应用)
我们首先进入findAdvisorsThatCanApply看下:
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
方法调用了AopUtils类(package org.springframework.aop.support中)的findAdvisorsThatCanApply方法。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
//刷选IntroductionAdvisor引介类型的通知器
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
//引介增强已经处理
continue;
}
//刷选普通类型的通知器
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
该函数调用了该类中的canApply方法,该方法实现了重载,其代码如下:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//使用 ClassFilter 匹配 class
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
/*
* 查找当前类及其父类(以及父类的父类等等)所实现的接口,由于接口中的方法是 public,
* 所以当前类可以继承其父类,和父类的父类中所有的接口方法
*/
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 获取当前类的方法列表,包括从父类中继承的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 使用 methodMatcher 匹配方法,匹配成功即可立即返回
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
/*
* 从通知器中获取类型过滤器 ClassFilter,并调用 matchers 方法进行匹配。
* ClassFilter 接口的实现类 AspectJExpressionPointcut 为例,该类的
* 匹配工作由 AspectJ 表达式解析器负责,具体匹配细节这个就没法分析了,我
* AspectJ 表达式的工作流程不是很熟
*/
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
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;
}
}
以上是通知器筛选的过程,筛选的工作主要由 ClassFilter 和 MethodMatcher 完成。
所以获取增强器的主要流程:(1)获取所有bean名称;(2)遍历所有bean名称找出其中标记Aspect的bean;(3)解析并构造获取bean的所有增强器;(4)将解析到的增强器添加到缓存中;(5)过滤匹配出当前bean的增强器。
(三)根据获取的增强创建代理
我们再回到AbstractAutoProxyCreator类的wrapIfNecessary方法。从这个方法代码中我们看到了代理创建的雏形。创建代理主要包含了两个步骤:1、获取增强方法或者增强器。2、根据获取的增强进行代理。上面我们介绍了获取增强方法或者增强器,下面我们看下根据获取的增强进行代理。
wrapIfNecessary函数中创建代理用了调用了Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
我们进入AbstractAutoProxyCreator类中的createProxy函数:
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();
//步骤1:获取当前类的属性。
proxyFactory.copyFrom(this);
//步骤2:添加代理接口。
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//步骤3:拦截器封装转化为增强器
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//步骤4:将Advisor加入到ProxyFactory中。
proxyFactory.addAdvisors(advisors);
//步骤5:设置要代理的类。
proxyFactory.setTargetSource(targetSource);
//步骤6:为子类提供了定制函数customizeProxyFactory
customizeProxyFactory(proxyFactory);
//步骤7:设置是否需要冻结代理对象。用来控制代理工厂被配置后,是否还允许修改通知。缺省值为false
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//步骤8:进行代理操作。
return proxyFactory.getProxy(getProxyClassLoader());
}
此函数主要是对ProxyFactory的初始化操作,进而对真正的代理创建做准备。这些初始化操作包括:
步骤1:获取当前类的属性。
步骤2:添加代理接口。
步骤3:拦截器封装转化为增强器
步骤4:将Advisor加入到ProxyFactory中。
步骤5:设置要代理的类。
步骤6:在Spring中还为子类提供了定制函数customizeProxyFactory,子类可以在此函数中对ProxyFactory进一步封装。
步骤7:设置是否需要冻结代理对象
步骤8:进行代理操作。
下面我们重点先来看下步骤3、4、8.
步骤3 :Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
步骤4:proxyFactory.addAdvisors(advisors);
步骤8: return proxyFactory.getProxy(getProxyClassLoader())
(1)步骤3:将拦截器封装转化为增强器。
首先要将拦截器封装转化为增强器,实现函数为buildAdvisors方法,在该类AbstractAutoProxyCreator中,代码如下:
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// 解析注册所有的InterceptorNames
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
//加入拦截器
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++) {
//将拦截器进行封装转化成Advisor
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
上述方法调用了接口advisorAdapterRegistry的wrap方法,DefaultAdvisorAdapterRegistry类(package org.springframework.aop.framework.adapter)是接口advisorAdapterRegistry的默认实现,用来完成各种通知的适配和注册过程。将Advice包装成Advisor(DefaultPointCutAdvisor),借助AdvisorAdapter,将Advisor包装成MethodInterceptor。我们进入此类中的wrap方法:
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
//如果要封装的对象本身就是Advisor类型的,那么无需再做过多的处理
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
//因为此封装方法只对Advisor与Advice两种类型的数据有效,如果不是将不能封装
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
//如果是MethodInterceptor类型,则使用DefaultPointcutAdvisor封装
return new DefaultPointcutAdvisor(advice);
}
//如果存在Advisor的适配器,那么也同样需要进行封装
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
(2)步骤4:将Advisor加入到ProxyFactory中。
将拦截器封装转化为增强器后,再通过ProxyFactory提供的addAdvisor方法将增强器置入创建工厂中。AbstractAutoProxyCreator.createProxy函数中直接调用了proxyFactory.addAdvisor (advisors)。proxyFactory继承自ProxyCreatorSupport,ProxyCreatorSupport继承自AdvisedSupport。addAdvisor这个方法实际在AdvisedSupport类(package org.springframework.aop.framework)中给出。
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
if (advisor instanceof IntroductionAdvisor) {
validateIntroductionAdvisor((IntroductionAdvisor) advisor);
}
addAdvisorInternal(pos, advisor);
}
(3)步骤8:进行获取代理操作。
我们再回到AbstractAutoProxyCreator.createProxy方法。最后一句代码:return proxyFactory.getProxy(getProxyClassLoader());进行解析最重要的一步就是代理类的创建和处理,Spring委托给了ProxyFactory去处理。我们进入ProxyFactory类(package org.springframework.aop.framework)中的getProxy函数。
public Object getProxy() {
// 调用了ProxyCreatorSupport的createAopProxy()方法创建一个AopProxy对象
// 然后调用AopProxy对象的getProxy方法
return createAopProxy().getProxy();
}
其中就一句话return createAopProxy().getProxy();。createAopProxy 方法没有在ProxyFactory类中定义,createAopProxy方法在其父类ProxyCreatorSupport(package org.springframework.aop.framework)中定义了,进入其代码:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 实际就是使用DefaultAopProxyFactory来创建一个代理对象
// 可以看到在调用createAopProxy方法时,传入的参数是this
// 这是因为ProxyCreatorSupport本身就保存了创建整个代理对象所需要的配置信息
return getAopProxyFactory().createAopProxy(this);
}
核心就一句代码return getAopProxyFactory().createAopProxy(this)。实际用的是AopProxyFactory类的createAopProxy方法。AopProxyFactory只是一个接口,DefaultAopProxyFactory(package org.springframework.aop.framework)是AopProxyFactory默认实现类,核心函数createAopProxy。所以其实是调用了DefaultAopProxyFactory类的createAopProxy方法。
@Override
// 就是通过AOP相关的配置信息来决定到底是使用cglib代理还是jdk代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果开启了优化,或者ProxyTargetClass设置为true
// 或者没有提供代理类需要实现的接口,那么使用cglib代理
// 在前面分析参数的时候已经说过了
// 默认情况下Optimize都为false,也不建议设置为true,因为会进行一些侵入性的优化
// 除非你对cglib的优化非常了解,否则不建议开启
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.");
}
// 需要注意的是,如果需要代理的类本身就是一个接口
// 或者需要被代理的类本身就是一个通过jdk动态代理生成的类
// 那么不管如何设置都会使用jdk动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
// 否则都是jdk代理
else {
return new JdkDynamicAopProxy(config);
}
}
至此完成了代理的创建。
本章内容节选自Spring框架之AOP源码完全解析 - tageerxing - 博客园 (cnblogs.com)
说是话没有完全看懂,先做个记录,以后再次观看。如有侵权,请提醒我,立刻删除!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?