AOP深入代理的创建
文章目录
- AOP深入代理的创建
-
- 一:AOP配置标签的配置
- 二:注解切面代理创建类
- 三:代理和AOP
-
- 1:动态代理要解决什么问题
- 2:Cglib动态代理
-
- 2.1:何为Cglib
- 2.2:Cglib代理的案例
- 2.3:Cglib代理的流程
- [2.4:Spring AOP中的Cglib代理](#2.4:Spring AOP中的Cglib代理)
- 3:JDK动态代理
-
- 3.1:JDK代理的案例
- 3.2:JDK代理的流程
- [3.3:Spring AOP中JDK代理](#3.3:Spring AOP中JDK代理)
一:AOP配置标签的配置
根据AOP的xml标签一路跟踪,可以跟踪到AOPNamespaceHandler方法
xml
<!-- config point cut -->
<aop:config>
<aop:pointcut id="pc" expression="execution(* *(..))"/>
<!-- 整合额外功能 -->
<aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>
java
/**
* 初始化方法,用于注册{@link BeanDefinitionParser BeanDefinition解析器},针对'config', 'spring-configured', 'aspectj-autoproxy'和'scoped-proxy'标签。
* 这个方法会分别注册这些标签对应的解析器,以便于在解析XML配置文件时,能够正确处理这些自定义标签。
* 其中,'config'和'aspectj-autoproxy'标签在2.0 XSD以及2.5+ XSD版本中均被支持;
* 'scoped-proxy'标签用于配置作用域代理;
* 'spring-configured'标签仅在2.0 XSD中存在,从2.5+版本开始,该功能被移动到了上下文命名空间中。
*/
@Override
public void init() {
// 注册'config'标签的解析器。该解析器用于处理配置相关的bean定义。
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
// 注册'aspectj-autoproxy'标签的解析器。该解析器用于启用并配置基于AspectJ的自动代理。
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
// 注册'scoped-proxy'标签的装饰器。该装饰器用于配置bean的作用域代理。
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// 仅注册'spring-configured'标签的解析器。该解析器用于处理Spring配置相关的bean定义,仅在2.0 XSD版本中有效。
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
1:config配置标签的解析
<aop:config/>
由ConfigBeanDefinitionParser这个类处理,作为parser类最重要的就是parse方法
java
/**
* 解析给定的XML元素,配置并注册相应的AOP组件。
*
* @param element 表示要解析的XML元素,包含了AOP配置信息。
* @param parserContext 解析上下文,用于处理元素和注册组件。
* @return 总是返回null,因为解析过程中不创建BeanDefinition。
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 创建一个组合组件定义,并基于当前元素设置来源信息
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 配置自动代理创建器
configureAutoProxyCreator(parserContext, element);
// 遍历并解析所有子元素,根据子元素的类型分别处理
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) { // <aop:pointcut> pointcut 切入点
// 解析切点元素
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) { // <aop:advisor> advice增强
// 解析advisor元素
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) { // <aop:aspect> aspect 切面
// 解析切面元素
parseAspect(elt, parserContext);
}
}
// 结束解析,弹出当前组件定义,并将其注册
parserContext.popAndRegisterContainingComponent();
return null;
}
parsePointcut -> //
<aop:pointcut> pointcut
切入点
java
/**
* 解析提供的 {@code <pointcut>} 元素,并将解析结果的 Pointcut 注册到 BeanDefinitionRegistry 中。
*
* @param pointcutElement pointcut元素,包含了pointcut的定义。
* @param parserContext 解析上下文,提供了注册表和其他解析环境的相关信息。
* @return 返回解析后生成的 Pointcut 的 BeanDefinition。
*/
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID); // 获取pointcut元素的ID属性
String expression = pointcutElement.getAttribute(EXPRESSION); // 获取pointcut元素的表达式属性
AbstractBeanDefinition pointcutDefinition = null;
try {
// 将当前解析状态推入栈中,用于跟踪解析过程
this.parseState.push(new PointcutEntry(id));
// 创建pointcut的bean定义
pointcutDefinition = createPointcutDefinition(expression);
// 设置pointcut定义的源信息
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id; // 默认使用id作为bean名称
if (StringUtils.hasText(pointcutBeanName)) {
// 如果有提供id,则注册这个pointcut定义到bean注册表中
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
// 如果没有提供id,则自动生成bean名称并注册
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
// 注册pointcut组件到解析上下文
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
// 不管是否抛出异常,最后都要把解析状态从栈中弹出
this.parseState.pop();
}
return pointcutDefinition; // 返回pointcut的bean定义
}
parseAdvisor() -> advice增强
java
/**
* 解析提供的{@code <advisor>}元素,并将得到的{@link org.springframework.aop.Advisor}和任何由此产生的{@link org.springframework.aop.Pointcut}
* 注册到提供的{@link BeanDefinitionRegistry}中。
*
* @param advisorElement 要解析的{@code <advisor>}元素。
* @param parserContext 解析上下文,包含用于注册Bean定义的注册表。
*/
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
// 创建Advisor的Bean定义
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
// 将当前解析状态推入栈中,用于跟踪解析过程
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
// 如果有有效的Bean名称,则注册Advisor Bean定义,否则使用自动生成的名称注册
if (StringUtils.hasText(advisorBeanName)) {
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
// 解析advisor元素中的pointcut属性,并处理pointcut
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
if (pointcut instanceof BeanDefinition) {
// 如果pointcut是一个Bean定义,则将其添加到Advisor Bean定义中,并注册组件
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
else if (pointcut instanceof String) {
// 如果pointcut是一个字符串引用,则将其作为运行时Bean引用添加到Advisor Bean定义中,并注册组件
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
}
finally {
// 不论解析成功与否,最后都需弹出当前解析状态
this.parseState.pop();
}
}
parseAspect() -> aspect切面标签的处理
java
/**
* 解析切面元素。
*
* @param aspectElement 表示切面的XML元素。
* @param parserContext 解析上下文,包含必要的工具和上下文信息。
*/
private void parseAspect(Element aspectElement, ParserContext parserContext) {
// 获取切面的ID和引用
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
// 将当前解析状态压入栈中,用于跟踪和错误处理
this.parseState.push(new AspectEntry(aspectId, aspectName));
// 初始化用于存储定义和引用的列表
List<BeanDefinition> beanDefinitions = new ArrayList<>();
List<BeanReference> beanReferences = new ArrayList<>();
// 解析declare-parents元素
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// 一次性解析所有类型的advice,以正确处理它们之间的顺序语义
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
// 如果尚未提供aspectName,则报错
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
// 添加对切面bean的引用
beanReferences.add(new RuntimeBeanReference(aspectName));
}
// 解析advice并添加到定义列表中
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
// 创建切面组件定义,并将其推入包含组件的上下文
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
// 解析切面中的pointcut元素
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
// 从上下文中弹出并注册当前包含的组件
parserContext.popAndRegisterContainingComponent();
}
finally {
// 无论是否发生异常,最后都需弹出解析状态
this.parseState.pop();
}
}
2:aspectj-autoproxy配置标签的解析
<aop:aspectj-autoproxy/>
则由AspectJAutoProxyBeanDefinitionParser这个类处理的,我们看下parse 方法
java
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册AspectJAnnotationAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 拓展BeanDefinition
extendBeanDefinition(element, parserContext);
return null;
}
/**
* 根据需要注册AspectJ注解自动代理创建器。
* 该方法会检查是否需要注册AspectJ注解自动代理创建器,并在必要时进行注册。
* 之后,根据情况使用类代理,并最后注册组件。
*
* @param parserContext 解析上下文,提供访问注册表和源元素的能力。
* @param sourceElement 源元素,代表正在处理的XML元素,用于提取相关信息。
*/
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册AspectJ注解自动代理创建器,如果尚未注册的话,并返回其Bean定义。
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 根据需要决定是否使用类代理。
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册组件,如果有必要的话。
registerComponentIfNecessary(beanDefinition, parserContext);
}
// 注册
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
到这里,我们发现AOP的创建工作是交给AnnotationAwareAspectJAutoProxyCreator来完成的
二:注解切面代理创建类
这个就是指AnnotationAwareAspectJAutoProxyCreator
它实现了两类接口:
- BeanFactoryAware属于Bean级生命周期接口方法
- InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为"后处理器",是容器级生命周期接口方法;
我们就可以定位到核心的初始化方法肯定在postProcessBeforeInstantiation和postProcessAfterInitialization中
1:postProcessBeforeInstantiation
java
/**
* 在实例化Bean之前进行后处理。
* 此方法用于判断是否需要为指定的Bean创建代理对象。如果需要创建代理,那么这里会负责创建并返回该代理对象。
*
* @param beanClass 待实例化的Bean的类对象。
* @param beanName 待实例化的Bean的名称。
* @return 如果为指定的Bean创建了代理对象,则返回该代理对象;否则返回null。
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
// 判断是否需要跳过代理的创建
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 检查该Bean是否已经被标记为不需要代理
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 是否是aop基础类?是否跳过?
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 判断是否需要基于自定义TargetSource创建代理
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
// 如果beanName不为空,则记录下该Bean是基于TargetSource的
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取针对该Bean的拦截器和advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 创建代理对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 记录代理类型
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
1.1:判断是否是AOP基础类
父类判断它是否是aop基础类的方法 super.isInfrastructureClass(beanClass),
本质上就是判断该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口
java
/**
* 判断给定的bean类是否代表一个不应被代理的基础设施类。
* <p>默认实现将Advices(通知)、Advisors(advisor)和AopInfrastructureBeans(AOP基础设施bean)视为基础设施类。
* @param beanClass bean的类
* @return 是否代表一个基础设施类
* @see org.aopalliance.aop.Advice
* @see org.springframework.aop.Advisor
* @see org.springframework.aop.framework.AopInfrastructureBean
* @see #shouldSkip
*/
protected boolean isInfrastructureClass(Class<?> beanClass) {
// 该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
// 如果是基础设施类,且日志记录级别为Trace,则输出日志
if (retVal && logger.isTraceEnabled()) {
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
}
return retVal;
}
1.2:是否应该跳过
java
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
/**
* 判断是否应该跳过给定的bean。
* 这个方法会检查是否存在一个对应的AspectJ切面advisor,如果存在,则跳过该bean。
*
* @param beanClass 待检查的bean的类对象。
* @param beanName 待检查的bean的名称。
* @return 如果应该跳过该bean,则返回true;否则返回false。
*/
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 考虑通过缓存切面名称列表来优化性能
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
// 检查当前advisor是否是一个AspectJ切点advisor,并且它的切面名称与beanName相等
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
// 如果没有找到匹配的AspectJ切点advisor,则调用超类的逻辑来决定是否跳过
return super.shouldSkip(beanClass, beanName);
}
1.3:切面方法转成Advisor
java
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
* 查找并返回所有候选的advisor(Advisor)。advisor是Spring AOP中的一种概念,代表了一种拦截器。
* 这个方法首先会调用父类的同名方法,获取按照父类规则找到的所有Springadvisor。
* 然后,如果存在AspectJadvisor构建器(aspectJAdvisorsBuilder),则会构建并添加所有AspectJ切面的advisor。
*
* @return 返回包含所有候选advisor的列表。这个列表可能包括了Spring AOPadvisor和AspectJadvisor。
*/
@Override
protected List<Advisor> findCandidateAdvisors() {
// 根据超类的规则添加所有找到的Springadvisor。
List<Advisor> advisors = super.findCandidateAdvisors();
// 如果存在AspectJadvisor构建器,则为bean工厂中的所有AspectJ切面构建advisor,并添加到列表中。
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
在当前的bean Factory中通过AspectJ注解的方式生成Advisor类,buildAspectJAdvisors()
方法如下
方法很长,但是逻辑很简单,本质上的思路是:用DCL双重锁的单例实现方式,拿到切面类里的切面方法,将其转换成advisor(并放入缓存中)
java
/**
* 在当前的bean工厂中查找被AspectJ注解的切面bean,并将它们表示为Spring AOPadvisor的列表返回。
* <p>为每个AspectJ通知方法创建一个Springadvisor。
* @return {@link org.springframework.aop.Advisor} beans的列表
* @see #isEligibleBean
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
// 如果没有缓存切面bean的名字,则进行查找和缓存
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 获取所有bean的名字,并检查每个bean是否为合适的切面
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// 排除不合适的bean
if (!isEligibleBean(beanName)) {
continue;
}
// 小心不要提前实例化bean,因为这样会导致Spring容器缓存未被织入的bean
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判断是否为切面,并根据切面的持久化模型处理
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 处理单例切面
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 对于单例bean,缓存advisor
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// 处理非单例切面
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
// 从缓存中获取或直接创建切面advisor
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
// <---------------- 转换的方法就是这个this.advisorFactory.getAdvisors(factory)
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
java
/**
* 获取给定方面实例工厂对应的advisor列表。
*
* @param aspectInstanceFactory 方面实例工厂,用于创建方面实例。
* @return advisor列表,每个advisor代表一个切面逻辑的执行点。
*/
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取方面类和方面名称进行验证
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// 将MetadataAwareAspectInstanceFactory包装成一个懒单例装饰器,确保方面实例只被实例化一次
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 遍历方面类中定义的advisor方法,创建对应的advisor对象
for (Method method : getAdvisorMethods(aspectClass)) {
// 由于Java 7后JDK返回的声明方法顺序不再保证与源代码中的顺序一致,因此此处硬编码声明顺序为0
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// 如果是按目标实例化方面,则添加一个虚拟的实例化advisor,用于确保方面的懒加载
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// 查找并添加方面的引入字段对应的advisor
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
对应的getAdvisor()
方法如下
java
/**
* 获取一个Advisor对象,它封装了切面的建议方法和切入点。
*
* @param candidateAdviceMethod 可能作为通知方法的候选方法。
* @param aspectInstanceFactory 提供方面实例的工厂,包含方面的元数据。
* @param declarationOrderInAspect 在方面内声明的顺序。
* @param aspectName 方面的名称。
* @return 如果能够为给定的建议方法创建一个Advisor,则返回该Advisor;否则返回null。
*/
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 验证方面的类是否有效
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获取一个切入点,基于候选建议方法和方面的类
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 创建并返回一个Advisor实例,包含切入点和建议方法
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
1.4:获取表达式的切点
获取表达式的切点的方法getPointcut如下:
java
/**
* 获取指定方法上的切点。
*
* @param candidateAdviceMethod 可能包含切面注解的候选建议方法。
* @param candidateAspectClass 候选切面的类。
* @return 如果找到切面注解,则返回一个配置好的AspectJExpressionPointcut实例;否则返回null。
*/
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 尝试在方法上找到AspectJ注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 创建一个AspectJ表达式切点,并配置表达式
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
// 如果设置了BeanFactory,则为切点设置BeanFactory
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
/**
* 在给定方法上查找并返回第一个AspectJ注解(无论如何应该只有一个)。
*
* @param method 要在其上查找AspectJ注解的方法。
* @return 如果找到第一个AspectJ注解,则返回该注解;如果没有找到,则返回null。
*/
@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
// 遍历AspectJ注解类集合,尝试在方法上找到第一个匹配的注解
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
// 找注解
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
// 如果找到注解,则直接返回
if (foundAnnotation != null) {
return foundAnnotation;
}
}
// 如果遍历完所有AspectJ注解类都没有找到注解,则返回null
return null;
}
/**
* 查找给定方法上特定类型的注解。
*
* @param method 要在其上查找注解的Method对象。
* @param toLookFor 要查找的注解的类型,是泛型A的Class对象。
* @return 如果找到了指定类型的注解,则返回一个封装了该注解的AspectJAnnotation对象;如果没有找到,则返回null。
* @param <A> 限定注解必须是Annotation的子类型,且为泛型方法的类型参数。
*/
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
// 通过AnnotationUtils工具类查找method上是否有toLookFor指定的注解
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
// 找到了指定的注解,封装并返回
return new AspectJAnnotation<>(result);
}
else {
// 未找到指定的注解,返回null
return null;
}
}
1.5:封装成为Advisor
Advisor 是 advice的包装器,包含了advice及其它信息
由InstantiationModelAwarePointcutAdvisorImpl构造完成
java
/**
* 构造函数:初始化一个AspectJ表达式切面顾问。
*
* @param declaredPointcut 声明的切点,即使用AspectJ表达式定义的切点。
* @param aspectJAdviceMethod AspectJ的通知方法,即切面中具体要执行的方法。
* @param aspectJAdvisorFactory 用于创建AspectJ顾问的工厂。
* @param aspectInstanceFactory 用于创建切面实例的工厂,支持延迟初始化。
* @param declarationOrder 声明顺序,用于排序多个切面。
* @param aspectName 切面的名称。
*
* 此构造函数根据切面实例化策略的不同,动态地处理切点和通知的绑定,要么直接实例化通知,要么延迟到首次使用时实例化。
*/
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
// 根据切面实例化方式决定切点和通知的处理方式
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 如果切面支持延迟初始化,则创建一个动态切点,该切点在切面实例化前后有不同的表现
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// 如果切面是单例模式,则直接实例化通知,并使用声明的切点
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 通过pointcut获取advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
通过pointcut获取advice
java
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
交给aspectJAdvisorFactory获取
java
/**
* 获取给定方法的建议,该方法是AspectJ切面的一部分。
*
* @param candidateAdviceMethod 可能包含AspectJ注解的候选建议方法。
* @param expressionPointcut 表示一个切点表达式的对象。
* @param aspectInstanceFactory 提供AspectJ切面实例的工厂。
* @param declarationOrder 切面声明的顺序。
* @param aspectName 切面的名称。
* @return 如果找到合适的建议,则返回一个Advice对象;如果没有找到或方法不是AspectJ注解的方法,则返回null。
*/
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 获取切面实例的类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 查找方法上的AspectJ注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 验证切面类的正确性
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
// 日志记录
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 根据注解类型创建相应的AspectJ建议对象
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
// 如果是切点方法,则不生成建议
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
// 设置返回值名称,如果存在
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
// 设置异常名称,如果存在
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// 最后将其它切面信息配置到advice
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
// 设置参数名称,如果可用
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
1.6:总结一下都干了什么
- 由IOC Bean加载方法栈中找到
parseCustomElement()
方法,找到aspectj-autoproxy的handler(aop.config.AopNamespaceHandler) - AopNamespaceHandler注册了
<aop:aspectj-autoproxy/>
的解析类是AspectJAutoProxyBeanDefinitionParser - AspectJAutoProxyBeanDefinitionParser的parse 方法 通过AspectJAwareAdvisorAutoProxyCreator类去创建
- AspectJAwareAdvisorAutoProxyCreator实现了两类接口,BeanFactoryAware和BeanPostProcessor:
- 根据Bean生命周期方法找到两个核心方法:
postProcessBeforeInstantiation
和postProcessAfterInitialization
- postProcessBeforeInstantiation:主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor
- postProcessAfterInitialization:主要负责将Advisor注入到合适的位置,创建代理(cglib或jdk),为后面给代理进行增强实现做准备。
- 根据Bean生命周期方法找到两个核心方法:
2:postProcessAfterInitialization
有了Adisor, 注入到合适的位置并交给代理(cglib和jdk)实现了。
java
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果不是提前暴露的代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果bean能够获取到advisor才创建代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary()
方法主要用于判断是否需要创建代理,如果Bean能够获取到advisor才需要创建代理
java
/**
* 如果必要,对给定的bean进行封装,即如果该bean符合被代理的条件。
* @param bean 需要检查是否需要被代理的原始bean实例
* @param beanName bean的名称
* @param cacheKey 用于访问元数据的缓存键
* @return 如果需要,返回封装了bean的代理对象;否则,直接返回原始bean实例
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果beanName不为空且该bean被标记为由目标源提供,则直接返回原始bean
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果该bean已经明确不需要被代理,则直接返回原始bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果该类是基础架构类或应该被跳过,则标记为不需要代理并返回原始bean
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果有相应的通知(advice),则创建代理对象 <-------- 获取所有的Advisor
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;
}
// 标记为不需要代理并返回原始bean
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
2.1:获取所有的Advisor
获取所有advisor的方法getAdvicesAndAdvisorsForBean()
java
/**
* 为指定的Bean获取适用的顾问(Advisor)数组和相应的代理(Proxy)配置。
* <p>
* 该方法会根据给定的Bean类、Bean名称以及可选的目标源(TargetSource),查找并返回一组适用的顾问对象。
* 如果没有找到任何适用的顾问,则返回一个特殊标记,表示不需要代理。
*
* @param beanClass 待代理的Bean的类对象。
* @param beanName 待代理的Bean的名称。
* @param targetSource 目标源,可为null。如果非null,它提供了一个特定的目标对象实例池。
* @return 一个包含所有适用顾问对象的数组,如果没有找到适用的顾问,则返回一个特殊标记。
*/
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 查找适用于当前Bean的全部Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
// 如果没有找到适用的Advisor,返回特殊标记,表示不需要代理
return DO_NOT_PROXY;
}
// 将找到的Advisor列表转换为Object数组并返回
return advisors.toArray();
}
通过findEligibleAdvisors方法获取advisor, 如果获取不到返回DO_NOT_PROXY(不需要创建代理)
java
/**
* 查找当前类的所有符合条件的Advisor。
* @param beanClass 需要查找Advisor的类
* @param beanName 当前代理bean的名称
* @return 如果没有找到切面或者拦截器,则返回空列表,不会返回{@code null}
* @see #findCandidateAdvisors 查找候选Advisor的方法
* @see #sortAdvisors 对Advisor进行排序的方法
* @see #extendAdvisors 扩展Advisor的方法
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 查找所有候选的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选出能够应用于当前类的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 扩展Advisor列表
extendAdvisors(eligibleAdvisors);
// 如果有符合条件的Advisor,则对其进行排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
获取所有切面类的切面方法生成Advisor:findCandidateAdvisors
java
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
找到这些Advisor中能够应用于beanClass的Advisor
java
/**
* 确定{@code candidateAdvisors}列表中适用于给定类的子列表。
* @param candidateAdvisors 待评估的顾问列表
* @param clazz 目标类
* @return 可适用于给定类的对象的顾问子列表(可能是原始列表本身)
*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 遍历所有顾问,找出适用于目标类的IntroductionAdvisor
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
// 遍历所有顾问,找出除了IntroductionAdvisor外,其他适用于目标类的顾问
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// 已经处理过IntroductionAdvisor,跳过
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
2.2:创建代理的入口方法
获取所有advisor后,如果有advisor,则说明需要增强,即需要创建代理。创建代理的方法【createProxy()
】如下:
java
/**
* 为给定的bean创建一个AOP代理。
* @param beanClass bean的类
* @param beanName bean的名称
* @param specificInterceptors 专门针对这个bean的一组拦截器(可能为空,但不能为null)
* @param targetSource 代理的目标源,已经预配置为访问该bean
* @return 该bean的AOP代理
* @see #buildAdvisors
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 如果beanFactory是可配置的列表bean工厂,则暴露目标类
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 根据是否使用代理目标类进行不同处理
if (proxyFactory.isProxyTargetClass()) {
// 显示处理JDK代理目标和lambda(用于引入建议场景)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// 必须允许引入;不能只将接口设置为代理的接口。
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// 没有强制使用proxyTargetClass标志,让我们应用默认检查...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 构建advisor数组
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 自定义代理工厂设置
customizeProxyFactory(proxyFactory);
// 设置代理工厂是否冻结以及是否预过滤顾问
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 在覆盖类加载器中加载bean类时使用原始类加载器
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
// 返回代理对象
return proxyFactory.getProxy(classLoader);
}
proxyFactory.getProxy(classLoader)
java
/**
* 根据工厂中的设置创建一个新的代理对象。
* <p>可以重复调用。如果增加了或删除了接口,其效果会有所不同。可以添加和删除拦截器。
* <p>如果需要创建代理对象,将使用给定的类加载器。
* @param classLoader 用于创建代理对象的类加载器(如果为 {@code null},则使用底层代理设施的默认类加载器)
* @return 代理对象
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
// 创建AOP代理并以其为基础生成代理对象
return createAopProxy().getProxy(classLoader);
}
2.3:依据条件创建代理(jdk或cglib)
java
/**
* 子类应该调用此方法来获取一个新的AOP代理。他们不应该使用{@code this}作为参数来创建一个AOP代理。
*
* @return 返回创建的AOP代理对象。
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
// 如果当前未激活,则激活代理
activate();
}
// 从AOP代理工厂获取并创建AOP代理
return getAopProxyFactory().createAopProxy(this);
}
java
public interface AopProxyFactory {
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
java
/**
* 创建AOP代理对象。
* 根据配置和目标对象的类型决定是使用JDK动态代理还是CGLIB代理。
*
* @param config 提供AOP代理所需配置的AdvisedSupport对象,包括目标对象、代理接口等信息。
* @return 返回一个AopProxy实例,可能是JdkDynamicAopProxy(使用JDK动态代理)或ObjenesisCglibAopProxy(使用CGLIB代理)。
* @throws AopConfigException 如果配置不正确,或者无法确定目标类时抛出。
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 检查是否在原生图像中运行,且是否满足使用CGLIB代理的条件
if (!NativeDetector.inNativeImage() &&
(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.");
}
// 判断目标类是否为接口、已代理类或Lambda类,是则使用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则,使用CGLIB代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 如果不满足使用CGLIB代理的条件,则默认使用JDK动态代理
return new JdkDynamicAopProxy(config);
}
}
几个要点
config.isOptimize()
是通过optimize设置,表示配置是自定义的,默认是false;config.isProxyTargetClass()
是通过<aop:config proxy-target-class="true" />
来配置的,表示优先使用cglib代理,默认是false;hasNoUserSuppliedProxyInterfaces(config)
表示是否目标类实现了接口
由此我们可以知道:
Spring默认在目标类实现接口时是通过JDK代理实现的,只有非接口的是通过Cglib代理实现的。
当设置proxy-target-class = true
时在目标类不是接口或者代理类时优先使用cglib代理实现。
三:代理和AOP
1:动态代理要解决什么问题
1.1:什么是代理
代理模式(Proxy pattern): 为另一个对象提供一个替身或占位符以控制对这个对象的访问
我(client)如果要买(doOperation)房,可以找中介(proxy)买房,中介直接和卖方(target)买房。
中介和卖方都实现买卖(doOperation)的操作。中介就是代理(proxy)。
1.2:什么是动态代理
动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。
在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。
可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作
2:Cglib动态代理
2.1:何为Cglib
Cglib是一个强大的、高性能的代码生成包
它广泛被许多AOP框架使用,为他们提供方法的拦截。
-
最底层是字节码
-
ASM是操作字节码的一个工具
- ASM 是一个通用的 Java 字节码操作和分析框架。
- 它可以用于修改现有类或直接以二进制形式动态生成类。
- ASM 提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。
- ASM 提供与其他 Java 字节码框架类似的功能,但专注于性能。
- 因为它的设计和实现尽可能小而且快,所以它非常适合在动态系统中使用
-
Cglib是基于ASM字节码工具操作字节码
- 生成动态代理,对target方法进行增强操作
-
Spring AOP是基于Cglib又进行了一层封装,实现了Cglib方式的动态代理
2.2:Cglib代理的案例
xml
<!-- cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
User实体类
java
/**
* <p>
* 功能描述:User实体类
* </p>
*
* @author cui haida
* @date 2024/04/11/20:26
*/
@Setter
@Getter
@AllArgsConstructor
@ToString
public class User {
private String name;
private int age;
}
目标类及其目标方法
java
/**
* <p>
* 功能描述:被代理的类 - 目标类 - target
* </p>
*
* @author cui haida
* @date 2024/04/11/20:27
*/
public class UserServiceImpl {
public List<User> findUserList() {
return Collections.singletonList(new User("cui haida", 18));
}
}
代理类
java
package org.example.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* <p>
* 功能描述:User Log Proxy
* </p>
*
* @author cui haida
* @date 2024/04/11/21:00
*/
public class UserLogProxy implements MethodInterceptor {
/**
* 业务类对象,供代理方法中进行真正的业务方法调用
*/
private Object target;
public Object getUserLogProxy(Object target) {
//给业务对象赋值
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
/**
* 代理方法,此方法会在目标方法执行前后打印日志。
*
* @param obj 目标对象,即被代理的对象。
* @param method 目标方法,即即将被调用的方法。
* @param args 目标方法的参数数组。
* @param proxy 方法代理对象,用于调用目标方法。
* @return 返回值为null,此处可根据实际需求修改。
* @throws Throwable 如果目标方法执行过程中抛出异常,则此处会抛出。
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 执行方法前打印日志
System.out.println("[before] execute method: " + method.getName());
// 调用目标方法,参数是目标方法和参数
Object result = proxy.invokeSuper(obj, args);
// 执行方法后打印日志,包括返回值
System.out.println("[after] execute method: " + method.getName() + ", return value: " + result);
return null;
}
}
Proxy Demo
java
public class ProxyDemo {
public static void main(String[] args) {
// proxy
UserServiceImpl userService = (UserServiceImpl) new UserLogProxy().getUserLogProxy(new UserServiceImpl());
// call methods
userService.findUserList();
}
}
2.3:Cglib代理的流程
- 通过Enhancer增强器将目标类动态创建动态代理类,通过在Enhancer中配置更多的参数来控制代理的行为,比如如果只希望增强这个类中的一个方法(而不是所有方法),那就增加callbackFilter来对目标类中方法进行过滤;Enhancer可以有更多的参数类配置其行为
- 动态生成的叫做
CGLIB$$addUser$$0()
,拦截器中使用的proxy.invokeSuper()
就是通过invoke方法调用CGLIB$$addUser$$0()
- final方法不能被代理,因为final方法没法被子类覆盖,当然不能代理了
2.4:Spring AOP中的Cglib代理
SpringAOP封装了cglib,通过其进行动态代理的创建。核心源码在CglibAopProxy的getProxy()
方法
java
@Override
public Object getProxy() {
return getProxy(null);
}
java
/**
* 创建CGLIB代理对象。
*
* @param classLoader 用于加载代理类的类加载器,如果为null,则使用默认的类加载器。代理对象将基于提供的类加载器或目标对象的类加载器进行创建。
* @return 返回创建的代理对象,该对象实现了目标类的所有接口。
*/
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
// 如果日志级别允许,记录创建CGLIB代理的开始信息
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;
// 检查目标类名称是否包含CGLIB的分隔符,以确定是否需要使用超类或接口进行代理
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
// 获取并添加目标类实现的所有接口到代理配置中
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 验证目标类是否可代理
validateClassIfNecessary(proxySuperClass, classLoader);
// 配置CGLIB Enhancer,准备生成代理类
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
// 检查类加载器是否支持类重载,如果是,则禁用CGLIB的缓存
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
// 设置代理需要实现的接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 设置代码生成策略,考虑类加载器
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();
}
// 在此点填充固定拦截器映射,仅在调用getCallbacks之后
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 生成代理类并实例化
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
// 抛出AOP配置异常,指示无法生成CGLIB子类
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) {
// 处理目标源获取失败的情况
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
获取callback的方法如下,提几个理解的要点吧,具体读者在学习的时候建议把我的例子跑一下,然后打一个断点进行理解。
rootClass
: 即目标代理类advised
: 包含上文中我们获取到的advisor增强器的集合exposeProxy
: 在xml配置文件中配置的,背景就是如果在事务A中使用了代理,事务A调用了目标类的的方法a,在方法a中又调用目标类的方法b,方法a,b同时都是要被增强的方法,如果不配置exposeProxy属性,方法b的增强将会失效,如果配置exposeProxy,方法b在方法a的执行中也会被增强了DynamicAdvisedInterceptor
: 拦截器将advised(包含上文中我们获取到的advisor增强器)构建配置的AOP的callback(第一个callback)targetInterceptor
: xml配置的optimize属性使用的(第二个callback)- 最后连同其它5个默认的Interceptor 返回作为cglib的拦截器链,之后通过CallbackFilter的accpet方法返回的索引从这个集合中返回对应的拦截增强器执行增强操作。
java
/**
* 获取回调数组,这些回调与AOP代理的调用密切相关。
*
* @param rootClass 方法作用的目标类
* @return Callback[] 回调数组,包含不同类型的回调对象以处理不同的调用情况。
* @throws Exception 如果在获取回调过程中发生错误,则抛出异常。
*/
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 根据不同的优化选择确定参数
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 选择一个"AOP"拦截器,用于AOP调用
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 选择一个直接到目标的拦截器。用于未经过AOP咨询的调用,但可能需要返回代理。
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
// 选择一个直接到目标的分发器,用于未经过AOP咨询的静态目标调用,不能返回代理。
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
// 主要回调数组的初始化,包括不同的拦截器和分发器
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // 用于正常的建议
targetInterceptor, // 优化调用目标,不考虑建议
new SerializableNoOp(), // 映射到此的方法无重写
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// 如果目标是静态的,并且建议链已冻结,则可以通过使用该方法的固定链直接将AOP调用发送到目标进行优化。
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);
// 为每个方法创建固定的回调链,用于优化内存
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(method, x);
}
// 将主要回调数组和固定回调数组的内容合并到回调数组中
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
3:JDK动态代理
JDK动态代理是有JDK提供的工具类Proxy实现的,每个代理实例(实现需要代理的接口)都有一个关联的调用处理程序对象
此对象实现了InvocationHandler,最终的业务逻辑是在InvocationHandler实现类的invoke方法上。
JDK代理不需要任何依赖。
3.1:JDK代理的案例
java
package org.example.proxy.jdk;
import org.example.proxy.User;
import java.util.List;
/**
* <p>
* 功能描述:JDK代理要求类必须要有接口
* </p>
*
* @author cui haida
* @date 2024/04/12/6:59
*/
public interface IUserService {
/**
* find all user
* @return 返回User集合
*/
List<User> findAllUser();
}
java
package org.example.proxy.jdk;
import org.example.proxy.User;
import java.util.Collections;
import java.util.List;
/**
* <p>
* 功能描述:接口实现类,目标类
* </p>
*
* @author cui haida
* @date 2024/04/12/7:00
*/
public class IUserServiceImpl implements IUserService {
@Override
public List<User> findAllUser() {
return Collections.singletonList(new User("cui haida", 13));
}
}
使用JDK动态代理完成代理工作,进行前后功能增强
java
package org.example.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* <p>
* 功能描述:JDK代理演示
* </p>
*
* @author cui haida
* @date 2024/04/12/6:59
*/
public class UserLogProxy {
// 目标接口
private IUserService target;
public UserLogProxy(IUserService target)
{
super();
this.target = target;
}
public IUserService getLoggingProxy() {
// 创建一个同接口的代理类
IUserService proxy;
// 获取类加载器
ClassLoader classLoader = target.getClass().getClassLoader(); // 获取目标对象的类加载器指定为代理类的类加载器也是这个
Class[] interfaces = {IUserService.class}; // 指定代理类实现的接口
InvocationHandler h = new InvocationHandler() {
/**
* proxy: 代理对象。 一般不使用该对象
* method: 正在被调用的方法
* args: 调用方法传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName(); // 拿到被代理方法的名称
/前置通知
System.out.println("[before] execute method: " + methodName);
// 调用方法
Object result = null;
try {
// <------------- 调用原始的方法
result = method.invoke(target, args);
// 返回通知, 可以访问到方法的返回值
} catch (NullPointerException e) {
e.printStackTrace();
// 异常通知, 可以访问到方法出现的异常
}
// 后置通知. 因为方法可以能会出异常, 所以访问不到方法的返回值
// log - after method
System.out.println("[after] execute method: " + methodName + ", return value: " + result);
return result;
}
};
/*
* loader: 代理对象使用的类加载器.
* interfaces: 指定代理对象的类型. 即代理代理对象中可以有哪些方法.
* h: 当具体调用代理对象的方法时, 应该如何进行响应, 实际上就是调用 InvocationHandler 的 invoke 方法
*/
proxy = (IUserService) Proxy.newProxyInstance(classLoader, interfaces, h);
return proxy;
}
}
java
package org.example.proxy.jdk;
/**
* <p>
* 功能描述:
* </p>
*
* @author cui haida
* @date 2024/04/12/7:08
*/
public class ProxyDemo {
public static void main(String[] args) {
// 拿到动态代理类
IUserService loggingProxy = new UserLogProxy(new IUserServiceImpl()).getLoggingProxy();
// 调用user
loggingProxy.findAllUser();
}
}
java
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这三个参数都是什么意思呢。首先再次强调代理开发的三个要素是 = 原始目标类 + 额外功能 + 和原始目标类实现相同的接口
其中原始目标类,需要我们自己声明
而额外功能需要我们通过第三个参数InvocationHandler h
来完成, 这个接口里有一个invoke方法,这个方法可以通过来实现额外功能的工作
第三个要求和原始目标类实现相同的接口需要我们通过第二个参数完成
而第一个参数classLoader就是借用一个加载器,创建代理类的一个class对象,进而可以创建代理对象【动态字节码】
3.2:JDK代理的流程
JDK代理自动生成的class是由sun.misc.ProxyGenerator来生成的。
java
public static byte[] generateProxyClass(final String name, // 名称
Class<?>[] interfaces, // interface接口
int accessFlags) // 权限
{
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
final byte[] classFile = gen.generateClassFile();
...
}
java
/**
* 生成代理类的类文件。此方法驱动类文件生成过程。
*
* @return 代理类的字节码数组
*/
private byte[] generateClassFile() {
// 初始化类文件,设置版本、访问标志、类名、父类名、接口名等信息
visit(V14, accessFlags, dotToSlash(className), null,
JLR_PROXY, typeNames(interfaces));
// 添加java.lang.Object类的hashCode、equals和toString方法的代理方法
// 之所以放在代理接口方法之前,是为了确保Object方法优先于接口中可能重复的方法
addProxyMethod(hashCodeMethod);
addProxyMethod(equalsMethod);
addProxyMethod(toStringMethod);
// 遍历所有代理接口,累积所有方法
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
if (!Modifier.isStatic(m.getModifiers())) {
addProxyMethod(m, intf);
}
}
}
// 对具有相同签名的代理方法集,验证方法的返回类型是否兼容
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
// 生成构造函数
generateConstructor();
// 为每个签名的方法生成代码:添加静态字段以存储Method对象,并生成代理方法代码
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 添加用于存储Method对象的私有静态最终字段
visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
LJLR_METHOD, null, null);
// 生成代理方法代码
pm.generateMethod(this, className);
}
}
// 生成静态初始化器和查找访问器方法
generateStaticInitializer();
generateLookupAccessor();
// 返回生成的类文件的字节码
return toByteArray();
}
一共三个步骤(把大象装进冰箱分几步?):
- 第一步:(把冰箱门打开)准备工作,将所有方法包装成ProxyMethod对象,包括Object类中hashCode、equals等方法,以及被代理的接口中的方法
- 第二步:(把大象装进去)为代理类组装字段,构造函数,方法,static初始化块等
- 第三步:(把冰箱门带上)写入class文件
所以总结下案例中的具体的流程如下:
- ProxyGenerator创建Proxy的具体类$Proxy0
- 由static初始化块初始化接口方法:2个IUserService接口中的方法,3个Object中的接口方法
- 由构造函数注入InvocationHandler
- 执行的时候,通过ProxyGenerator创建的Proxy,调用InvocationHandler的invoke方法,执行我们自定义的invoke方法
3.3:Spring AOP中JDK代理
SpringAOP扮演的是JDK代理的创建和调用两个角色【JdkDynamicAopProxy类】
SpringAOP JDK代理的创建
代理的创建比较简单,调用getProxy方法,然后直接调用JDK中Proxy.newProxyInstance()方法将classloader和被代理的接口方法传入即可
java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
// ....;
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 代理实例
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
// ....;
}
SpringAOP JDK代理的执行
java
/**
* 实现{@code InvocationHandler.invoke}方法。
* <p>调用者将看到目标抛出的精确异常,除非钩子方法抛出异常。
* @param proxy 代理对象,即调用此方法的对象。
* @param method 被调用的方法。
* @param args 方法调用的参数数组。
* @return 方法的返回值,类型为Object。
* @throws Throwable 如果目标方法抛出异常,则会抛出异常。
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null; // 用于存储之前设置的当前代理对象,以便后续恢复
boolean setProxyContext = false; // 标记是否设置了代理上下文
TargetSource targetSource = this.advised.targetSource; // 获取目标源
Object target = null; // 存储从目标源获取的目标对象
try {
// 处理特殊情况:目标对象未实现equals方法时,调用invoker的equals方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
// 处理特殊情况:目标对象未实现hashCode方法时,直接调用invoker的hashCode方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
// 处理代理类自身声明的方法,如getDecoratedClass()
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 允许对代理配置的服务调用
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果需要暴露代理,则设置当前线程的代理上下文
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 尽可能晚地获取目标对象,以减少持有目标对象的时间,特别是从池中获取的情况
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取此方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 检查是否有拦截器,如果没有,直接使用反射调用目标方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建方法调用实例,并通过拦截器链执行
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
// 如果返回值需要调整,进行处理
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 特殊情况处理:返回值为"this"且方法的返回类型与代理类型兼容
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
// 如果返回值为null且方法预期返回原生类型,则抛出异常
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
// 释放目标对象,如果目标源是非静态的
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
// 恢复之前的代理上下文
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}