spring-aop bean的创建

demo搭建

AopConfig.java

package com.yhw.aop;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @author 蒙ym
 * @Date 2021/1/20
 */
@ComponentScans({@ComponentScan("com.yhw.aop.*"),@ComponentScan("com.yhw.aop")})
//开启aop功能!!!这个注解很重要!!!核心注解!!!
// 在spring中,@Component也可以当成配置类,这里可以省略@Configuartion
@EnableAspectJAutoProxy
public class AopConfig {
}

AopService.java

package com.yhw.aop;

import com.yhw.pojo.User;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service("aopService")
public class AopService {

    public String aopService(String name, List<String> list, Map<String,List<String>> map, User user){
      System.err.println("测试aop的service......");
      return "success";
    }
}

package com.yhw.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author 蒙ym
 * @Date 2020/12/11
 */
@Aspect
@Component
public class LogPrintAspect {

    @Pointcut("execution(* com.yhw.aop.AopService.aopService(..))")
    public void method(){};

    @Before("method()")
    public void before(JoinPoint joinPoint){
        System.err.println("before~~~~~~");
        System.err.println(joinPoint.toString());
        System.err.println("before~~~~~~");
    }

    @After("method()")
    public void afrer(JoinPoint joinPoint){
        System.err.println("after~~~~~~");
        System.err.println(joinPoint.toString());
        System.err.println("after~~~~~~");
    }

    @Around("method()")
    public Object arround(ProceedingJoinPoint pjp) {
        System.out.println("方法环绕start.....");
        try {
            Object o =  pjp.proceed();
            System.err.println("方法环绕proceed,结果是 :" + o);
            return o;
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }
}

package com.yhw.aop;

import com.yhw.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 蒙ym
 * @Date 2021/1/20
 */
public class AopMainApplication {

    public static void main(String[] args) {
    	// 注解工厂
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
        // 获取bean
        AopService aopService = applicationContext.getBean("aopService", AopService.class);
        String name = "我是测试名字";
        List<String> list = new ArrayList<>();
        list.add("我是测试的list");
        Map<String,List<String>> map = new HashMap<>();
        map.put(name, list);
        User user = new User();
        user.setName("张三丰");
        aopService.aopService(name, list, map, user);
    }
}

开始调试

  1. @EnableAspectJAutoProxy注解的作用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// @Import导入其他配置文件,,导入了一个自动代理的bean解析器
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}

@Import导入的bean也会被解析到ioc中,并且他也会被当成一个配置类,去解析他里面定义的需要注入的bean

  1. aop模式下的bd加载
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

着重解析ImportBeanDefinitionRegistrar.java

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	// 最终代码会走到这里进行aop的beanDefinition处理
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		//给容器添加一个bd,名字为org.springframework.aop.config.internalAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 获取配置类的@EnableAspectJAutoProxy注解
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		// 将注解里面的ProxyTargetClass与exposeProxy的值设置给上面加载的bd里面
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
}

到这里,ioc容器多了一个bean为org.springframework.aop.config.internalAutoProxyCreator
他的类型为AnnotationAwareAspectJAutoProxyCreator类型,那么注入他的作用是什么呢?
继承关系
在这里插入图片描述
从上图可以看出AspectJAwareAdvisorAutoProxyCreator是Aware接口的实现类
bean加载—>设置属性—>初始化,其中就有判断bean是否实现了Aware接口(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware),如果有就会执行相关方法(设置beanname,beanClassLoader,BeanFactory)

本次aop注入的bean实现了BeanFactoryWare接口,在执行相关方法后,会持有IOC容器的引用。
看下具体代码:invokeAwareMethods方法

private void invokeAwareMethods(String beanName, Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware)bean).setBeanName(beanName);
            }

            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
                }
            }
			//在这里设置ioc容器的引用
            if (bean instanceof BeanFactoryAware) {
            	//往下看
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }
    }

设置IOC容器引用

AbstractAdvisorAutoProxyCreator   25  line

public void setBeanFactory(BeanFactory beanFactory) {
        super.setBeanFactory(beanFactory);
        if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
            throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
        } else {
        	//初始化beanFactory  继续往下看
            this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
        }
    }

初始化BeanFactory

AnnotationAwareAspectJAutoProxyCreator  46  line

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		//创建了advisorRetrievalHelper 
        super.initBeanFactory(beanFactory);
        if (this.aspectJAdvisorFactory == null) {
            this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        }
		//初始化aspectJAdvisorsBuilder
        this.aspectJAdvisorsBuilder = new AnnotationAwareAspectJAutoProxyCreator.BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    }

如果有初始化awareBeanPostProcessor,则进行下面解析
在这里插入图片描述
设置IOC容器的引用
在这里插入图片描述
aop中的BeanPostProcessor做以下操作
在这里插入图片描述
loadBeanDefinitonFromRegistrars从注册中加载BeanDefinition,迭代获取
在这里插入图片描述
容器注册bd
在这里插入图片描述
初始化前的解析包装
在这里插入图片描述
参数的绑定(shouldSkip)
AspectAwareAdvisorAutoProxyCreator
在这里插入图片描述

总结

  1. 每个子接口都定义了set方法。而方法中的形参是接口**Aware(感知)**前面的内容,也就是当前Bean需要感知的内容。所以我们需要在Bean中声明相关的成员变量来接收。
  2. aware,对bean的增强,没实现aware接口的bean进不了容器,实现aware接口可进到容器中完成框架的绑定,操作透明可见,但同时耦合度也会变高。没必要纠结理论,类似setBeanFactory对bean工厂的初始化都要过aware接口。
  3. advisors和aspect的区别:
    2.1 Advisors只包含一个pointcut和一个Advisor
    2.2 Aspect包含多个poinct和多个advisor,
    2.3 Aspect定义切面、advice和切入点
    2.4 Advisors定义advisor,切入点和通知器,且必须实现advisor接口

流程图

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级无敌暴龙战士塔塔开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值