IoC原理
核心类
BeanFactory
ApplicationContext:
ApplicationContext 是一个接口,提供了访问 Spring 容器的 API
ClassPathXmlApplicationContext 是一个类,实现了上述功能
ApplicationContext 的顶层接口是 BeanFactory
BeanFactory 定义了 bean 相关的最基本操作
ApplicationContext 在 BeanFactory 基础上追加了若干新功能
ApplicationContext 和 BeanFactory对比:
BeanFactory 和 ApplicationContext 是 Spring 的两大核心接口,都可以当做 Spring 的容器
BeanFactory 是 Spring 里面最底层的接口,是 IoC 的核心,定义了 IoC 的基本功能,包含了各种 Bean 的定义、加载、实例化,依赖注入和生命周期管理。ApplicationContext 接口作为 BeanFactory 的子类,除了提供 BeanFactory 所具有的功能外,还提供了更完整的框架功能:
- 继承 MessageSource,因此支持国际化
- 资源文件访问,如 URL 和文件(ResourceLoader)。
- 载入多个(有继承关系)上下文(即加载多个配置文件) ,使得每一个上下文都专注于一个特定的层次,比如应用的 web 层
- 提供在监听器中注册 bean 的事件
BeanFactory 创建的 bean 采用延迟加载形式,只有在使用到某个 Bean 时(调用 getBean),才对该 Bean 进行加载实例化(Spring 早期使用该方法获取 bean),这样就不能提前发现一些存在的 Spring 的配置问题;ApplicationContext 是在容器启动时,一次性创建了所有的 Bean,容器启动时,就可以发现 Spring 中存在的配置错误,这样有利于检查所依赖属性是否注入
ApplicationContext 启动后预载入所有的单实例 Bean,所以程序启动慢,运行时速度快
两者都支持 BeanPostProcessor、BeanFactoryPostProcessor 的使用,但两者之间的区别是:BeanFactory 需要手动注册,而 ApplicationContext 则是自动注册
FileSystemXmlApplicationContext:加载文件系统中任意位置的配置文件,而 ClassPathXmlAC 只能加载类路径下的配置文件

BeanFactory 的成员属性:
String FACTORY_BEAN_PREFIX = "&";
- 区分是 FactoryBean 还是创建的 Bean,加上 & 代表是工厂,getBean 将会返回工厂
- FactoryBean:如果某个 bean 的配置非常复杂,或者想要使用编码的形式去构建它,可以提供一个构建该 bean 实例的工厂,这个工厂就是 FactoryBean 接口实现类,FactoryBean 接口实现类也是需要 Spring 管理
- 这里产生两种对象,一种是 FactoryBean 接口实现类(IOC 管理),另一种是 FactoryBean 接口内部管理的对象
- 获取 FactoryBean 接口实现类,使用 getBean 时传的 beanName 需要带 & 开头
- 获取 FactoryBean 内部管理的对象,不需要带 & 开头
BeanFactory 的基本使用:
Resource res = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(res);
UserService userService = (UserService)bf.getBean("userService");
FactoryBean
FactoryBean:对单一的 bean 的初始化过程进行封装,达到简化配置的目的
代码实现:
FactoryBean,实现类一般是 MapperFactoryBean,创建 DAO 层接口的实现类
public class EquipmentDaoImplFactoryBean implements FactoryBean { @Override //获取Bean public Object getObject() throws Exception { return new EquipmentDaoImpl(); } @Override //获取bean的类型 public Class<?> getObjectType() { return null; } @Override //是否单例 public boolean isSingleton() { return false; } }MapperFactoryBean 继承 SqlSessionDaoSupport,可以获取 SqlSessionTemplate,完成 MyBatis 的整合
public abstract class SqlSessionDaoSupport extends DaoSupport { private SqlSessionTemplate sqlSessionTemplate; // 获取 SqlSessionTemplate 对象 public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) { this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory); } } }
两者区别:
- BeanFactory:IoC容器顶层接口,给IoC容器提供了一套完整的规范。以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。
- FactoryBean:也是一个工厂类接口,用户可以通过该接口定制实例化Bean的逻辑,Spring自身就提供了70多个FactoryBean的实现,他们隐藏了一些实例化复杂Bean的细节,从而给上层应用带来便捷
过滤器
数据准备
DAO 层 UserDao、AccountDao、BookDao、EquipmentDao
public interface UserDao { public void save(); }@Component("userDao") public class UserDaoImpl implements UserDao { public void save() { System.out.println("user dao running..."); } }Service 业务层
public interface UserService { public void save(); }@Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao;//...........BookDao等 public void save() { System.out.println("user service running..."); userDao.save(); } }
过滤器
名称:TypeFilter
类型:接口
作用:自定义类型过滤器
示例:
config / filter / MyTypeFilter
public class MyTypeFilter implements TypeFilter { @Override /** * metadataReader:读取到的当前正在扫描的类的信息 * metadataReaderFactory:可以获取到任何其他类的信息 */ //加载的类满足要求,匹配成功 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //获取当前类注解的信息 AnnotationMetadata am = metadataReader.getAnnotationMetadata(); //获取当前正在扫描的类的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前类资源(类的路径) Resource resource = metadataReader.getResource(); //通过类的元数据获取类的名称 String className = classMetadata.getClassName(); //如果加载的类名满足过滤器要求,返回匹配成功 if(className.equals("service.impl.UserServiceImpl")){ //返回true表示匹配成功,返回false表示匹配失败。此处仅确认匹配结果,不会确认是排除还是加入,排除/加入由配置项决定,与此处无关 return true; } return false; } }SpringConfig
@Configuration //设置排除bean,排除的规则是自定义规则(FilterType.CUSTOM),具体的规则定义为MyTypeFilter @ComponentScan( value = {"dao","service"}, excludeFilters = @ComponentScan.Filter( type= FilterType.CUSTOM, classes = MyTypeFilter.class ) ) public class SpringConfig { }
导入器
bean 只有通过配置才可以进入 Spring 容器,被 Spring 加载并控制
配置 bean 的方式如下:
- XML 文件中使用
标签配置 - 使用 @Component 及衍生注解配置
- XML 文件中使用
导入器可以快速高效导入大量 bean,替代 @Import({a.class,b.class}),无需在每个类上添加 @Bean
名称: ImportSelector
类型:接口
作用:自定义bean导入器
selector / MyImportSelector
public class MyImportSelector implements ImportSelector{ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 1.编程形式加载一个类 // return new String[]{"dao.impl.BookDaoImpl"}; // 2.加载import.properties文件中的单个类名 // ResourceBundle bundle = ResourceBundle.getBundle("import"); // String className = bundle.getString("className"); // 3.加载import.properties文件中的多个类名 ResourceBundle bundle = ResourceBundle.getBundle("import"); String className = bundle.getString("className"); return className.split(","); } }import.properties
#2.加载import.properties文件中的单个类名 #className=dao.impl.BookDaoImpl #3.加载import.properties文件中的多个类名 #className=dao.impl.BookDaoImpl,dao.impl.AccountDaoImpl #4.导入包中的所有类 path=dao.impl.*SpringConfig
@Configuration @ComponentScan({"dao","service"}) @Import(MyImportSelector.class) public class SpringConfig { }
注册器
可以取代 ComponentScan 扫描器
名称:ImportBeanDefinitionRegistrar
类型:接口
作用:自定义 bean 定义注册器
registrar / MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类,把所有需要添加到容器中的bean调用registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //自定义注册器 //1.开启类路径bean定义扫描器,需要参数bean定义注册器BeanDefinitionRegistry,需要制定是否使用默认类型过滤器 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry,false); //2.添加包含性加载类型过滤器(可选,也可以设置为排除性加载类型过滤器) scanner.addIncludeFilter(new TypeFilter() { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //所有匹配全部成功,此处应该添加实际的业务判定条件 return true; } }); //设置扫描路径 scanner.addExcludeFilter(tf);//排除 scanner.scan("dao","service"); } }SpringConfig
@Configuration @Import(MyImportBeanDefinitionRegistrar.class) public class SpringConfig { }
处理器
通过创建类继承相应的处理器的接口,重写后置处理的方法,来实现拦截 Bean 的生命周期来实现自己自定义的逻辑
BeanPostProcessor:bean 后置处理器,bean 创建对象初始化前后进行拦截工作的
BeanFactoryPostProcessor:beanFactory 的后置处理器
加载时机:在 BeanFactory 初始化之后调用,来定制和修改 BeanFactory 的内容;所有的 bean 定义已经保存加载到 beanFactory,但是 bean 的实例还未创建执行流程:- ioc 容器创建对象
- invokeBeanFactoryPostProcessors(beanFactory):执行 BeanFactoryPostProcessor
- 在 BeanFactory 中找到所有类型是 BeanFactoryPostProcessor 的组件,并执行它们的方法
- 在初始化创建其他组件前面执行
BeanDefinitionRegistryPostProcessor:
加载时机:在所有 bean 定义信息将要被加载,但是 bean 实例还未创建,优先于 BeanFactoryPostProcessor 执行;利用 BeanDefinitionRegistryPostProcessor 给容器中再额外添加一些组件
执行流程:
- ioc 容器创建对象
- refresh() → invokeBeanFactoryPostProcessors(beanFactory)
- 从容器中获取到所有的 BeanDefinitionRegistryPostProcessor 组件
- 依次触发所有的 postProcessBeanDefinitionRegistry() 方法
- 再来触发 postProcessBeanFactory() 方法
监听器
基本概述
ApplicationListener:监听容器中发布的事件,完成事件驱动模型开发
public interface ApplicationListener<E extends ApplicationEvent>
所以监听 ApplicationEvent 及其下面的子事件
应用监听器步骤:
写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)把监听器加入到容器 @Component只要容器中有相关事件的发布,就能监听到这个事件;ContextRefreshedEvent:容器刷新完成(所有 bean 都完全创建)会发布这个事件ContextClosedEvent:关闭容器会发布这个事件
发布一个事件:`applicationContext.publishEvent()`
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
//当容器中发布此事件以后,方法触发
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到事件:" + event);
}
}
实现原理
ContextRefreshedEvent 事件:
容器初始化过程中执行
initApplicationEventMulticaster():初始化事件多播器- 先去容器中查询
id = applicationEventMulticaster的组件,有直接返回 - 没有就执行
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory)并且加入到容器中 - 以后在其他组件要派发事件,自动注入这个 applicationEventMulticaster
- 先去容器中查询
容器初始化过程执行 registerListeners() 注册监听器
- 从容器中获取所有监听器:
getBeanNamesForType(ApplicationListener.class, true, false) - 将 listener 注册到 ApplicationEventMulticaster
- 从容器中获取所有监听器:
容器刷新完成:finishRefresh() → publishEvent(new ContextRefreshedEvent(this))
发布 ContextRefreshedEvent 事件:
- 获取事件的多播器(派发器):getApplicationEventMulticaster()
- multicastEvent 派发事件
- 获取到所有的 ApplicationListener
- 遍历 ApplicationListener
- 如果有 Executor,可以使用 Executor 异步派发
Executor executor = getTaskExecutor() - 没有就同步执行 listener 方法
invokeListener(listener, event),拿到 listener 回调 onApplicationEvent
- 如果有 Executor,可以使用 Executor 异步派发
容器关闭会发布 ContextClosedEvent
注解实现
注解:@EventListener
基本使用:
@Service
public class UserService{
@EventListener(classes={ApplicationEvent.class})
public void listen(ApplicationEvent event){
System.out.println("UserService。。监听到的事件:" + event);
}
}
原理:使用 EventListenerMethodProcessor 处理器来解析方法上的 @EventListener,Spring 扫描使用注解的方法,并为之创建一个监听对象
SmartInitializingSingleton 原理:afterSingletonsInstantiated()
IOC 容器创建对象并 refresh()finishBeanFactoryInitialization(beanFactory):初始化剩下的单实例 bean- 先创建所有的单实例 bean:getBean()
- 获取所有创建好的单实例 bean,判断是否是 SmartInitializingSingleton 类型的,如果是就调用 afterSingletonsInstantiated()
AOP原理
注解原理
@EnableAspectJAutoProxy:AOP 注解驱动,给容器中导入 AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
// 是否强制使用 CGLIB 创建代理对象
// 配置文件方式:<aop:aspectj-autoproxy proxy-target-class="true"/>
boolean proxyTargetClass() default false;
// 将当前代理对象暴露到上下文内,方便代理对象内部的真实对象拿到代理对象
// 配置文件方式:<aop:aspectj-autoproxy expose-proxy="true"/>
boolean exposeProxy() default false;
}
AspectJAutoProxyRegistrar 在用来向容器中注册 AnnotationAwareAspectJAutoProxyCreator,以 BeanDefiantion 形式存在,在容器初始化时加载。AnnotationAwareAspectJAutoProxyCreator 间接实现了 InstantiationAwareBeanPostProcessor,Order 接口,该类会在 Bean 的实例化和初始化的前后起作用
工作流程:创建 IOC 容器,调用 refresh() 刷新容器,registerBeanPostProcessors(beanFactory) 阶段,通过 getBean() 创建 AnnotationAwareAspectJAutoProxyCreator 对象,在生命周期的初始化方法中执行回调 initBeanFactory() 方法初始化注册三个工具类:BeanFactoryAdvisorRetrievalHelperAdapter、ReflectiveAspectJAdvisorFactory、BeanFactoryAspectJAdvisorsBuilderAdapter
后置处理
Bean 初始化完成的执行后置处理器的方法:
public Object postProcessAfterInitialization(@Nullable Object bean,String bN){
if (bean != null) {
// cacheKey 是 【beanName 或者加上 & 的 beanName】
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 去提前代理引用池中寻找该 key,不存在则创建代理
// 如果存在则证明被代理过,则判断是否是当前的 bean,不是则创建代理
return wrapIfNecessary(bean, bN, cacheKey);
}
}
return bean;
}
AbstractAutoProxyCreator.wrapIfNecessary():根据通知创建动态代理,没有通知直接返回原实例
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 条件一般不成立,很少使用 TargetSourceCreator 去创建对象 BeforeInstantiation 阶段,doCreateBean 之前的阶段
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// advisedBeans 集合保存的是 bean 是否被增强过了
// 条件成立说明当前 beanName 对应的实例不需要被增强处理,判断是在 BeforeInstantiation 阶段做的
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 条件一:判断当前 bean 类型是否是基础框架类型,这个类的实例不能被增强
// 条件二:shouldSkip 判断当前 beanName 是否是 .ORIGINAL 结尾,如果是就跳过增强逻辑,直接返回
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 【查找适合当前 bean 实例的增强方法】(下一节详解)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 条件成立说明上面方法查询到适合当前class的通知
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 根据查询到的增强创建代理对象(下一节详解)
// 参数一:目标对象
// 参数二:beanName
// 参数三:匹配当前目标对象 clazz 的 Advisor 数据
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);
// 【返回原始的 bean 实例】
return bean;
}
获取通知
AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean():查找适合当前类实例的增强,并进行排序
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 查询适合当前类型的增强通知
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
// 增强为空直接返回 null,不需要创建代理
return DO_NOT_PROXY;
}
// 不是空,转成数组返回
return advisors.toArray();
}
AbstractAdvisorAutoProxyCreator.findEligibleAdvisors():
candidateAdvisors = findCandidateAdvisors():获取当前容器内可以使用(所有)的 advisor,调用的是 AnnotationAwareAspectJAutoProxyCreator 类的方法,每个方法对应一个 Advisoradvisors = super.findCandidateAdvisors():查询出 XML 配置的所有 Advisor 类型advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors():通过 BF 查询出来 BD 配置的 class 中 是 Advisor 子类的 BeanNameadvisors.add():使用 Spring 容器获取当前这个 Advisor 类型的实例
advisors.addAll(....buildAspectJAdvisors()):获取所有添加 @Aspect 注解类中的 AdvisorbuildAspectJAdvisors():构建的方法,把 Advice 封装成 AdvisorbeanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false):获取出容器内 Object 所有的 beanName,就是全部的for (String beanName : beanNames):遍历所有的 beanName,判断每个 beanName 对应的 Class 是否是 Aspect 类型,就是加了 @Aspect 注解的类factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName):使用工厂模式管理 Aspect 的元数据,关联的真实 @Aspect 注解的实例对象classAdvisors = this.advisorFactory.getAdvisors(factory):添加了 @Aspect 注解的类的通知信息aspectClass:@Aspect 标签的类的 class
for (Method method : getAdvisorMethods(aspectClass)):遍历不包括 @Pointcut 注解的方法Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName):将当前 method 包装成 Advisor 数据AspectJExpressionPointcut expressionPointcut = getPointcut():获取切点表达式return new InstantiationModelAwarePointcutAdvisorImpl():把 method 中 Advice 包装成 Advisor,Spring 中每个 Advisor 内部一定是持有一个 Advice 的,Advice 内部最重要的数据是当前 method 和aspectInstanceFactory,工厂用来获取实例this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut):实例化 Advice 对象,逻辑是获取注解信息,根据注解的不同生成对应的 Advice 对象
advisors.addAll(classAdvisors):保存通过 @Aspect 注解定义的 Advisor 数据
this.aspectBeanNames = aspectNames:将所有 @Aspect 注解 beanName 缓存起来,表示提取 Advisor 工作完成return advisors:返回 Advisor 列表
eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, ...):选出匹配当前类的增强if (candidateAdvisors.isEmpty()):条件成立说明当前 Spring 没有可以操作的 AdvisorList<Advisor> eligibleAdvisors = new ArrayList<>():存放匹配当前 beanClass 的 Advisors 信息for (Advisor candidate : candidateAdvisors):遍历所有的 Advisorif (canApply(candidate, clazz, hasIntroductions)):判断遍历的 advisor 是否匹配当前的 class,匹配就加入集合if (advisor instanceof PointcutAdvisor):创建的 advisor 是 InstantiationModelAwarePointcutAdvisorImpl 类型PointcutAdvisor pca = (PointcutAdvisor) advisor:封装当前 Advisorreturn canApply(pca.getPointcut(), targetClass, hasIntroductions):重载该方法if (!pc.getClassFilter().matches(targetClass)):类不匹配 Pointcut 表达式,直接返回 falsemethodMatcher = pc.getMethodMatcher():获取 Pointcut 方法匹配器,类匹配进行类中方法的匹配Set<Class<?>> classes:保存目标对象 class 和目标对象父类超类的接口和自身实现的接口if (!Proxy.isProxyClass(targetClass)):判断当前实例是不是代理类,确保 class 内存储的数据包括目标对象的class 而不是代理类的 classfor (Class<?> clazz : classes):检查目标 class 和上级接口的所有方法,查看是否会被方法匹配器匹配,如果有一个方法匹配成功,就说明目标对象 AOP 代理需要增强specificMethod = AopUtils.getMostSpecificMethod(method, targetClass):方法可能是接口的,判断当前类有没有该方法return (specificMethod != method && matchesMethod(specificMethod)):类和方法的匹配,不包括参数
extendAdvisors(eligibleAdvisors):在 eligibleAdvisors 列表的索引 0 的位置添加 DefaultPointcutAdvisor,封装了 ExposeInvocationInterceptor 拦截器eligibleAdvisors = sortAdvisors(eligibleAdvisors):对拦截器进行排序,数值越小优先级越高,高的排在前面- 实现 Ordered 或 PriorityOrdered 接口,PriorityOrdered 的级别要优先于 Ordered,使用 OrderComparator 比较器
- 使用 @Order(Spring 规范)或 @Priority(JDK 规范)注解,使用 AnnotationAwareOrderComparator 比较器
- ExposeInvocationInterceptor 实现了 PriorityOrdered ,所以总是排在第一位,MethodBeforeAdviceInterceptor 没实现任何接口,所以优先级最低,排在最后
return eligibleAdvisors:返回拦截器链
创建代理
AbstractAutoProxyCreator.createProxy():根据增强方法创建代理对象
ProxyFactory proxyFactory = new ProxyFactory():无参构造 ProxyFactory,此处讲解一下两种有参构造方法:public ProxyFactory(Object target):
public ProxyFactory(Object target) { // 将目标对象封装成 SingletonTargetSource 保存到父类的字段中 setTarget(target); // 获取目标对象 class 所有接口保存到 AdvisedSupport 中的 interfaces 集合中 setInterfaces(ClassUtils.getAllInterfaces(target)); }ClassUtils.getAllInterfaces(target) 底层调用 getAllInterfacesForClassAsSet(java.lang.Class<?>, java.lang.ClassLoader):
if (clazz.isInterface() && isVisible(clazz, classLoader)):- 条件一:判断当前目标对象是接口
- 条件二:检查给定的类在给定的 ClassLoader 中是否可见
Class<?>[] ifcs = current.getInterfaces():拿到自己实现的接口,拿不到接口实现的接口current = current.getSuperclass():递归寻找父类的接口,去获取父类实现的接口
public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor):
public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) { // 添加一个代理的接口 addInterface(proxyInterface); // 添加通知,底层调用 addAdvisor addAdvice(interceptor); }addAdvisor(pos, new DefaultPointcutAdvisor(advice)):Spring 中 Advice 对应的接口就是 Advisor,Spring 使用 Advisor 包装 Advice 实例
proxyFactory.copyFrom(this):填充一些信息到 proxyFactoryif (!proxyFactory.isProxyTargetClass()):条件成立说明 proxyTargetClass 为 false(默认),两种配置方法:<aop:aspectj-autoproxy proxy-target-class="true"/>:强制使用 CGLIB@EnableAspectJAutoProxy(proxyTargetClass = true)
if (shouldProxyTargetClass(beanClass, beanName)):如果 bd 内有 preserveTargetClass = true ,那么这个 bd 对应的 class 创建代理时必须使用 CGLIB,条件成立设置 proxyTargetClass 为 trueevaluateProxyInterfaces(beanClass, proxyFactory):根据目标类判定是否可以使用 JDK 动态代理targetInterfaces = ClassUtils.getAllInterfacesForClass():获取当前目标对象 class 和父类的全部实现接口boolean hasReasonableProxyInterface = false:实现的接口中是否有一个合理的接口if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) && ifc.getMethods().length > 0):遍历所有的接口,如果有任意一个接口满足条件,设置 hRPI 变量为 true- 条件一:判断当前接口是否是 Spring 生命周期内会回调的接口
- 条件二:接口不能是 GroovyObject、Factory、MockAccess 类型的
- 条件三:找到一个可以使用的被代理的接口
if (hasReasonableProxyInterface):有合理的接口,将这些接口设置到 proxyFactory 内proxyFactory.setProxyTargetClass(true):没有合理的代理接口,强制使用 CGLIB 创建对象
advisors = buildAdvisors(beanName, specificInterceptors):匹配目标对象 clazz 的 Advisors,填充至 ProxyFactoryproxyFactory.setPreFiltered(true):设置为 true 表示传递给 proxyFactory 的 Advisors 信息做过基础类和方法的匹配return proxyFactory.getProxy(getProxyClassLoader()):创建代理对象public Object getProxy() { return createAopProxy().getProxy(); }DefaultAopProxyFactory.createAopProxy(AdvisedSupport config):参数是一个配置对象,保存着创建代理需要的生产资料,会加锁创建,保证线程安全
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 条件二为 true 代表强制使用 CGLIB 动态代理 if (config.isOptimize() || config.isProxyTargetClass() || // 条件三:被代理对象没有实现任何接口或者只实现了 SpringProxy 接口,只能使用 CGLIB 动态代理 hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException(""); } // 条件成立说明 target 【是接口或者是已经被代理过的类型】,只能使用 JDK 动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); // 使用 JDK 动态代理 } return new ObjenesisCglibAopProxy(config); // 使用 CGLIB 动态代理 } else { return new JdkDynamicAopProxy(config); // 【有接口的情况下只能使用 JDK 动态代理】 } }JdkDynamicAopProxy.getProxy(java.lang.ClassLoader):获取 JDK 的代理对象
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { // 配置类封装到 JdkDynamicAopProxy.advised 属性中 this.advised = config; } public Object getProxy(@Nullable ClassLoader classLoader) { // 获取需要代理的接口数组 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); // 查找当前所有的需要代理的接口,看是否有 equals 方法和 hashcode 方法,如果有就做一个标记 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 该方法最终返回一个代理类对象 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); // classLoader:类加载器 proxiedInterfaces:生成的代理类,需要实现的接口集合 // this JdkDynamicAopProxy 实现了 InvocationHandler }AopProxyUtils.completeProxiedInterfaces(this.advised, true):获取代理的接口数组,并添加 SpringProxy 接口
specifiedInterfaces = advised.getProxiedInterfaces():从 ProxyFactory 中拿到所有的 target 提取出来的接口if (specifiedInterfaces.length == 0):如果没有实现接口,检查当前 target 是不是接口或者已经是代理类,封装到 ProxyFactory 的 interfaces 集合中
addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class):判断目标对象所有接口中是否有 SpringProxy 接口,没有的话需要添加,这个接口标识这个代理类型是 Spring 管理的addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class):判断目标对象的所有接口,是否已经有 Advised 接口addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)):判断目标对象的所有接口,是否已经有 DecoratingProxy 接口int nonUserIfcCount = 0:非用户自定义的接口数量,接下来要添加上面的三个接口了proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount]:创建一个新的 class 数组,长度是原目标对象提取出来的接口数量和 Spring 追加的数量,然后进行 System.arraycopy 拷贝到新数组中int index = specifiedInterfaces.length:获取原目标对象提取出来的接口数量,当作 indexif(addSpringProxy):根据上面三个布尔值把接口添加到新数组中return proxiedInterfaces:返回追加后的接口集合
JdkDynamicAopProxy.findDefinedEqualsAndHashCodeMethods():查找在任何定义在接口中的 equals 和 hashCode 方法
for (Class<?> proxiedInterface : proxiedInterfaces):遍历所有的接口Method[] methods = proxiedInterface.getDeclaredMethods():获取接口中的所有方法for (Method method : methods):遍历所有的方法if (AopUtils.isEqualsMethod(method)):当前方法是 equals 方法,把 equalsDefined 置为 trueif (AopUtils.isHashCodeMethod(method)):当前方法是 hashCode 方法,把 hashCodeDefined 置为 true
if (this.equalsDefined && this.hashCodeDefined):如果有一个接口中有这两种方法,直接返回
方法增强
main() 函数中调用用户方法,会进入代理对象的 invoke 方法
JdkDynamicAopProxy 类中的 invoke 方法是真正执行代理方法
// proxy:代理对象,method:目标对象的方法,args:目标对象方法对应的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// advised 就是初始化 JdkDynamicAopProxy 对象时传入的变量
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 条件成立说明代理类实现的接口没有定义 equals 方法,并且当前 method 调用 equals 方法,
// 就调用 JdkDynamicAopProxy 提供的 equals 方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
} //.....
Object retVal;
// 需不需要暴露当前代理对象到 AOP 上下文内
if (this.advised.exposeProxy) {
// 【把代理对象设置到上下文环境】
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 根据 targetSource 获取真正的代理对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 查找【适合该方法的增强】,首先从缓存中查找,查找不到进入主方法【下文详解】
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 拦截器链是空,说明当前 method 不需要被增强
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 有匹配当前 method 的方法拦截器,要做增强处理,把方法信息封装到方法调用器里
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())) {
// 如果目标方法返回目标对象,这里做个普通替换返回代理对象
retVal = proxy;
}
// 返回执行的结果
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
// 如果允许了提前暴露,这里需要设置为初始状态
if (setProxyContext) {
// 当前代理对象已经完成工作,【把原始对象设置回上下文】
AopContext.setCurrentProxy(oldProxy);
}
}
}
this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass):查找适合该方法的增强,首先从缓存中查找,获取通知时是从全部增强中获取适合当前类的,这里是从当前类的中获取适合当前方法的增强
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance():向容器注册适配器,可以将非 Advisor 类型的增强,包装成为 Advisor,将 Advisor 类型的增强提取出来对应的 MethodInterceptorinstance = new DefaultAdvisorAdapterRegistry():该对象向容器中注册了 MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter 三个适配器Advisor 中持有 Advice 对象
public interface Advisor { Advice getAdvice(); }
advisors = config.getAdvisors():获取 ProxyFactory 内部持有的增强信息interceptorList = new ArrayList<>(advisors.length):拦截器列表有 5 个,1 个 ExposeInvocation和 4 个增强器actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()):真实的目标对象类型Boolean hasIntroductions = null:引介增强,不关心for (Advisor advisor : advisors):遍历所有的 advisor 增强if (advisor instanceof PointcutAdvisor):条件成立说明当前 Advisor 是包含切点信息的,进入匹配逻辑pointcutAdvisor = (PointcutAdvisor) advisor:转成可以获取到切点信息的接口if(config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)):当前代理被预处理,或者当前被代理的 class 对象匹配当前 Advisor 成功,只是 class 匹配成功mm = pointcutAdvisor.getPointcut().getMethodMatcher():获取切点的方法匹配器,不考虑引介增强match = mm.matches(method, actualClass):静态匹配成功返回 true,只关注于处理类及其方法,不考虑参数if (match):如果静态切点检查是匹配的,在运行的时候才进行动态切点检查,会考虑参数匹配(代表传入了参数)。如果静态匹配失败,直接不需要进行参数匹配,提高了工作效率interceptors = registry.getInterceptors(advisor):提取出当前 advisor 内持有的 advice 信息Advice advice = advisor.getAdvice():获取增强方法if (advice instanceof MethodInterceptor):当前 advice 是 MethodInterceptor 直接加入集合for (AdvisorAdapter adapter : this.adapters):遍历三个适配器进行匹配(初始化时创建的),匹配成功创建对应的拦截器返回,以 MethodBeforeAdviceAdapter 为例if (adapter.supportsAdvice(advice)):判断当前 advice 是否是对应的 MethodBeforeAdviceinterceptors.add(adapter.getInterceptor(advisor)):条件成立就往拦截器链中添加 advisoradvice = (MethodBeforeAdvice) advisor.getAdvice():获取增强方法return new MethodBeforeAdviceInterceptor(advice):封装成 MethodBeforeAdviceInterceptor 返回
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)):向拦截器链添加动态匹配器interceptorList.addAll(Arrays.asList(interceptors)):将当前 advisor 内部的方法拦截器追加到 interceptorList
interceptors = registry.getInterceptors(advisor):进入 else 的逻辑,说明当前 Advisor 匹配全部 class 的全部 method,全部加入到 interceptorListreturn interceptorList:返回 method 方法的拦截器链
retVal = invocation.proceed():拦截器链驱动方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1):条件成立说明方法拦截器全部都已经调用过了(index 从 - 1 开始累加),接下来需要执行目标对象的目标方法return invokeJoinpoint():调用连接点(目标)方法this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex):获取下一个方法拦截器if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher):需要运行时匹配if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)):判断是否匹配成功return dm.interceptor.invoke(this):匹配成功,执行方法return proceed():匹配失败跳过当前拦截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this):一般方法拦截器都会执行到该方法,此方法内继续执行 proceed() 完成责任链的驱动,直到最后一个 MethodBeforeAdviceInterceptor 调用前置通知,然后调用 mi.proceed(),发现是最后一个拦截器就直接执行连接点(目标方法),return 到上一个拦截器的 mi.proceed() 处,依次返回到责任链的上一个拦截器执行通知方法
图示先从上往下建立链,然后从下往上依次执行,责任链模式
正常执行:(环绕通知)→ 前置通知 → 目标方法 → 后置通知 → 返回通知
出现异常:(环绕通知)→ 前置通知 → 目标方法 → 后置通知 → 异常通知
MethodBeforeAdviceInterceptor 源码:
public Object invoke(MethodInvocation mi) throws Throwable { // 先执行通知方法,再驱动责任链 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); // 开始驱动目标方法执行,执行完后返回到这,然后继续向上层返回 return mi.proceed(); }AfterReturningAdviceInterceptor 源码:没有任何异常处理机制,直接抛给上层
public Object invoke(MethodInvocation mi) throws Throwable { // 先驱动责任链,再执行通知方法 Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }AspectJAfterThrowingAdvice 执行异常处理:
public Object invoke(MethodInvocation mi) throws Throwable { try { // 默认直接驱动责任链 return mi.proceed(); } catch (Throwable ex) { // 出现错误才执行该方法 if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } }
