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