本篇内容主要讲解“如何理解AOP中JDK代理实现的原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解AOP中JDK代理实现的原理”吧!
动态代理技术在Spring AOP中分为两种:
提供一种在运行时创建一个实现了一组接口的新类。由于Java是不支持实例化接口的,因此JDK会在运行期间生成一个代理类对给定的接口进行实现,在调用该代理类接口的时候,将实现逻辑转发到调用处理器中(Invocation handler)。
JDK进行动态代理的类必须实现接口
代理类是java.lang.reflect.Proxy子类,类名以$Proxy开始。
CGLIB(Code Generation Library)是基于ASM(对Java字节码进行操作的框架)的类库。
Spring AOP中,如果被代理类(targetObject)没有实现接口,即无法通过JDK的动态代理生成代理类,那么就会选择CGLIB来进行代理。
CGLIB动态代理的原理:创建一个targetObject的子类,覆盖掉需要父类的方法,在覆盖的方法中对功能进行增强。
注意,由于是采用继承覆盖的方式,所以由final方法修饰的类无法使用CGLIB进行代理。
JDK动态代理要求被代理类实现接口,切面类需要实现InvocationHandler。
CGLIB采用继承+方法覆盖实现切面,重写方法将逻辑委托给MethodInterceptor#intercept。
CGLIB对代理类基本没有限制,但是需要注意被代理的类不可以被final修饰符和private修饰,因为Java无法重写final类/private的方法。
@EnableAspectJAutoProxy注解是Spring AOP开启的标志,在启动类标记此注解,即启用可加载对应的切面类逻辑。此注解的ElementType为TYPE,表示标记在类上。
同时用 @Retention(RetentionPolicy.RUNTIME) 声明了注解在运行时得到保留。此外最重要的是使用了 @Import(AspectJAutoProxyRegistrar.class) 来注册AOP的。
@EnableAspectJAutoProxy注解正是通过@Import的方式来将 AspectJAutoProxyRegistrar类注册成Spring的Bean,以便在容器解析切面类时派上用场。那么AspectJAutoProxyRegistrar类的作用是什么?
@Import(AspectJAutoProxyRegistrar.class)
@EnableAspectJAutoProxy支持处理标有AspectJ的@Aspect批注的组件,用户可以主动声明proxyTargetClass来指定Spring AOP使用哪种动态代理方式来创建代理类(默认使用基于实现接口的JDK动态代理方式)。
使用CGLIB动态代理来创建代理类
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
@ComponentScan("com.libo")
public class AppConfig {
// ...
}
为了解决一些由于代理引发的切面失效问题,Spring AOP在Spring 4.3.1后引入了AopContext类来将代理类的引用存储在ThreadLocal中,通过AopContext可以快速获取当前类的代理类。
默认为不支持,如果声明为true,即可使用AopContext获取代理类,同时,为了使用AspectJ,需要确保当前jar仓库存在aspectjweaver。
通过@Import注册AspectJAutoProxyRegistrar,通常情况下,我们的启动类本身也是一个Bean,Spring支持使用 @Import来导入一个没有标记任何Spring注解 的类来将该Java类注册成Spring的Bean。
Registers an AnnotationAwareAspectJAutoProxyCreator against the current BeanDefinitionRegistry as appropriate based on a given @EnableAspectJAutoProxy annotation.
根据当前BeanDefinitionRegistry在适当的位置注册AnnotationAwareAspectJAutoProxyCreator。
用来导入一些特殊的BeanDefinition,Spring在处理 @Configuration 时,会去扫描是否有通过 @Import 标签导入的类,对ImportBeanDefinitionRegistrar这类接口,还会执行其中的registerBeanDefinitions方法。
AspectJAutoProxyRegistrar:实现了ImportBeanDefinitionRegistrar接口,用来注册AspectJAnnotationAutoProxyCreator,也就是支持注解驱动(同时兼容XML)解析的AspectJ自动代理创建器。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 向容器注册AspectJAnnotationAutoProxyCreator
AopConfigUtils.
registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata,
EnableAspectJAutoProxy.class);
// 如果@EnableAspectJAutoProxy上存在标签内容
if (enableAspectJAutoProxy != null) {
// proxyTargetClass为true,则强制指定AutoProxyCreator使用CGLIB进行代理
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 是否开启exposeProxy特性
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
向容器注册AspectJAnnotationAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
随后解析 @EnableAspectJAutoProxy 注解上的元数据来决定是否开启上述我们讲到的proxyTargetClass和exposeProxy特性.
为了了解registerBeanDefinitions方法的执行链路和调用时机,我们使用IDE的debug来查看调用栈分析执行流程。
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass(configClass.getImportBeanDefinitionRegistrars())
这行代码,从代码的语义上我们可以大致可以猜出来,这是解析当前配置类上是否存在通过@Import导入的实现了ImportBeanDefinitionRegistrar的类。
最终会调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,注册一个AnnotationAwareAspectJAutoProxyCreator,该类属于AOP的核心类。
执行AspectJAutoProxyRegistrar#registerBeanDefinitions方法。
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
从上面的代码可以看出来AnnotationAwareAspectJAutoProxyCreator这个类作为实际操作者,查看该类的继承关系图。(省略一些不必要的类)。
首先看第一个接口,BeanPostProcessor,这个接口作为顶层接口,肯定不会被外部直接调用,所以大概率是底下的几个具体实现类被调用,然后通过判断是不是InstantiationAwareBeanPostProcessor接口的类型,再执行相应逻辑,带着这个疑惑,来看源码。
AbstractAutoProxyCreator通过postProcessAfterInitialization实现AOP功能。
// 在实例化之后进行操作容器对象
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String
beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object
cacheKey) {
// beanName不为空,并且存在于targetSourcedBeans中,也就是自定义的
// TargetSource被解析过了
if (StringUtils.hasLength(beanName) &&
this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果Bean为advisedBeans,也不需要被代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// isInfrastructureClass和shouldSkip的作用:
// 识别切面类,加载切面类成advisors
// 为什么又执行一次是因为存在循环依赖的情况下无法加载advisor
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),
beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 返回匹配当前Bean的所有Advice、Advisor、Interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),
beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息
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;
}
判断缓存中是否存在当前Bean或者是当前Bean已经被代理过了,那么直接返回bean.
尝试再次加载advisor,避免由于循环依赖导致advisor加载不完整.
获取当前bean符合的advisor数组.
创建代理类.
本文来分析getAdvicesAndAdvisorsForBean方法是如何在所有的advisors中找到匹配的advisor的.
@Override
@Nullable
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来寻找合适的advisors,如果返回的集合为空,那么 // 最后返回null.
// 如果返回了advisors,将其数组化返回.
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String
beanName) {
//BeanFactory 中所有 Advisor 的实现
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 有资格的 Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors,
beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
//首先获取之前解析过的advisors列表-candidateAdvisors,这里是所有的切面类解析成的advisors.
//在candidateAdvisors中找到当前Bean匹配的advisor-findAdvisorsThatCanApply.
//将获取到的eligibleAdvisors进行排序.
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No
BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
// 存储最终匹配的Advisor集合
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// 当前advisor对象是否实现了IntroductionAdvisor接口
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// canApply->判断当前的advisor的pointcut表达式是否匹配当前class
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
//最终是调用了AopUtils.findAdvisorsThatCanApply来筛选匹配Bean的Advisors.
ProxyFactory 对象中有要代理的bean和这个Bean上的advisor
Bean使用哪种代理
当Bean实现接口时,Spring就会用JDK的动态代理。 当Bean没有实现接口时,Spring会自动使用CGlib实现,但是前提是项目中导入了CGlib的相关依赖,否则Spring只能使用JDK来代理那些没有实现接口的类,这样生成的代理类会报错。 AopProxy有两个实现类JdkDynamicAopProxy和CglibAopProxy。都是构造 ReflectiveMethodInvocation.proceed()。
JdkDynamicAopProxy
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
CglibAopProxy
// CglibMethodInvocation 继承于 ReflectiveMethodInvocation
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
ReflectiveMethodInvocation.proceed()
public Object proceed() throws Throwable {
// 当所有拦截器都执行后,调用目标类的目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 动态拦截器
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// MethodInterceptor的实现类在处理完自己的逻辑后,还是会调用procee(),传入this就是为了达到这个目的
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
Spring用来处理应用上下文中被@AspectJ注解标记的类的。继续进入registerOrEscalateApcAsRequired方法中看看注册流程.
org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 当前容器是否包含 org.springframework.aop.config.internalAutoProxyCreator
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) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 将传入的class包装成BeanDefinition,然后注册到容器中,并讲其order的执行顺序
//调整为最优。
// 在aop中,这里会注册AnnotationAwareAspectJAutoProxyCreator.class这个类
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;
}
首先查看当前容器中是否包含
org.springframework.aop.config.internalAutoProxyCreator的BeanDefiniton.
如果没有,将传入的class(在此处传入了AnnotationAwareAspectJAutoProxyCreator.class)包装成RootBeanDefinition,然后注册到容器中.
设置proxyTargetClass与exposeProxy
我们看一下如何设置proxyTargetClass即可,大体上设置proxyTargetClass与exposeProxy的逻辑都是相通的.
// 如果@EnableAspectJAutoProxy上存在标签内容
if (enableAspectJAutoProxy != null) {
// 如果proxyTargetClass为true,则强制指定AutoProxyCreator使用CGLIB进行代理
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 是否开启exposeProxy特性
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
进入AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
AopConfigUtils#forceAutoProxyCreatorToUseClassProxying
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
// 如果容器中包含 org.springframework.aop.config.internalAutoProxyCreator
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 取出 org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition
BeanDefinition definition =
registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 设置proxyTargetClass为true
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
如容器中包含名org.springframework.aop.config.internalAutoProxyCreator,那么取出该BeanDefinition,设置proxyTargetClass为true。
Spring为了兼容不同的BeanDefinition持有不同的属性值,将它们都抽象成了MutablePropertyValues,definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE),就跟我们平时JavaBean中的set方法是一样的.
简单理解 @Import 和ImportBeanDefinitionRegistrar,下面我们通过两个用例来理解@Import和ImportBeanDefinitionRegistrar
通过@Import导入类让Spring进行管理
public class NeedImportBean {
public void doSomething(){
Logger.getGlobal().info("Through @Import registry to a bean ");
}
}
在启动类中将NeedImportBean导入
/**
* @author jaymin
* 2020/11/30 20:13
*/
@Configuration
@ComponentScan(value = "com.xjm")
@Import(NeedImportBean.class)
@EnableAspectJAutoProxy
public class ApplicationConfig {
public static AnnotationConfigApplicationContext getApplicationContext() {
return new AnnotationConfigApplicationContext(ApplicationConfig.class);
}
}
//对NeedImportBean做getBean
public class BeanFactoryDemo {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext =
ApplicationConfig.getApplicationContext();
NeedImportBean needImportBean =
applicationContext.getBean(NeedImportBean.class);
}
}
NeedImportBean实现ImportBeanDefinitionRegistrar接口,然后验证两个点:
是否会回调registerBeanDefinitions方法。
通过getBean是否能获取NeedImportBean
public class NeedImportBean implements ImportBeanDefinitionRegistrar{
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Logger.getGlobal().info("Through implements ImportBeanDefinitionRegistrar and @Import to callback me.");
}
public void doSomething(){
Logger.getGlobal().info("Through @Import registry to a bean ");
}
}
refresh中激活后置处理器ConfigurationClassPostProcessor加载@Configuration上的元数据
首先容器会加载refresh方法。
执行invokeBeanFactoryPostProcessors(beanFactory);激活工厂级别的后置处理器。
由于启动类都是被 @Configuration 标记的,Spring会使用ConfigurationClassPostProcessor来解析被 @Configuration 的类。
使用ConfigurationClassBeanDefinitionReader来加载配置类解析成BeanDefinition。
到此,相信大家对“如何理解AOP中JDK代理实现的原理”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/liboware/blog/5051727