spring-6-源码解析AOP-及扩展知识
原理图
https://www.processon.com/apps/5d1c16dde4b076f4fd3f5c40
package com.beanPostProcessor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.PriorityOrdered; import org.springframework.stereotype.Component; @Component public class Lwj_BeanPostPocessor implements BeanPostProcessor, PriorityOrdered { //实现PriorityOrdered,实现getOrder方法返回一个数值越小越靠前执行 @Override public int getOrder() { return 102; } //初始化之前植入的切面方法 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if("wjwTest".equals(beanName)){ System.out.println("Lwj_BeanPostPocessor之前的方法"); } return bean; } //初始化之后植入的切面方法 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if("wjwTest".equals(beanName)){ System.out.println("Lwj_BeanPostPocessor之后的方法"); } return bean; } }
此方式是spring提供的扩展点之一,spring中一共存在五种扩展方式。
再应用中单例(singleton)调用原型(prototype)可以使用两种方式
Lookup方式 需要注意的是@Lookup只能注解在方法上,这个时候可以注解在一个抽象方法上。
实现ApplicationContextAware接口实现set方法,此方式是重新创建一个beanFactory然后从工厂中再获取一个bean此时这个newBean与原工厂中的oldBean类型一致但在JVM的堆中不属于同一个
spring最重要的类
configurationClassPostProcessor
引出ImportBeanDefinitionRegistrar,实现此接口可以获取beanFactory中的map(容器),之后可以注册bean对象到map中
spring初始化内部重要的6个类对象 是在ApplicationContext初始化之前,使用AnnotatedBeanDefinitionReader方法,将spring会将内置处理前读取到map中
internalConfigurationAnnotationProcessor
internalAutowiredAnnotationProcessor
internalCommonAnnotationProcessor
internalEventListenerProcessor
PersistenceAnnotationBeanPostProcessor
internalEventListenerFactory
spring-扩展
扩展接口
BeanPostProcessor,可以在bean初始化前后干涉bean中的逻辑 postProcessBeforeInitialization() postProcessAfterInitialization()
PriorityOrdered,可以按照顺序加载bean getOrder()
ImportBeanDefinitionRegistrar,spring-mtbaits使用的方式是将一个BeanDefinition动态添加到工厂map中 registerBeanDefinitions()
BeanFactoryPostProcessor,是bean初始化前最后一次允许修改BeanDefinition信息,可以直接从DefinitionFactory中获取BeanDefinition,然后修改属性(此方法不建议使用)postProcessBeanFactory()
模拟spring-mybatis代码
当做SqlSessionFactory
package com.dao; public interface MapperDao { public void query(); }
实现ImportBeanDefinitionRegistrar 重写 registerBeanDefinitions方法
package com.MyImport; import com.dao.MapperDao; import com.mapperFactoryBean.MapperFactoryBean; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; public class ImplMapperImportBean implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { /** * 此处可以获取当前包下的某一个类,进行循环注册自己的bean * 思路: * 1、创建一个definition * 2、制定definition的BeanClass的属性,为一个bean指定一个类(实现FactoryBean,注意特性下面beanName为例getBean("mapperDao")获取的是factoryBean中的getObject()返回的对象) * 3、为这个bean指定return构造函数参数值,因为构造中可以无参也可以有参,我们使用构造函数中的参数对象的数量及类型来判断调用的构造方法,也就是我们getBean获取的对象 * 4、使用beanfactory中的registerBeanDefinition方法将BeanDefinition注册到我们的工厂 * */ BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MapperDao.class); GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition(); System.out.println(genericBeanDefinition.getBeanClassName()); genericBeanDefinition.setBeanClass(MapperFactoryBean.class); genericBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.dao.MapperDao"); registry.registerBeanDefinition("mapperDao",genericBeanDefinition); } }
FactoryBean
package com.mapperFactoryBean; import org.springframework.beans.factory.FactoryBean; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MapperFactoryBean implements FactoryBean, InvocationHandler { /** * 此处有扩展 * 此处利用spring中自动装配(类型3种:ByName、ByType、Constructor)构造我们想注入到IOC容器中的bean * spring中装配方式一共有五种 * 分别是 * on Spring框架的默认设置 * byName 不了解的话这段也不用学了 * byType 不了解的话这段也不用学了 * constructor 不了解的话这段也不用学了 * AutoDetect 如果没有无参构造则默认使用constructor方式,如果有无参构造则使用byType方式setter注入 * 我们这里使用构造 * */ Class clazz; public MapperFactoryBean(Class clazz) { this.clazz = clazz; } //实现InvocationHandle接口重写invoke方法,这里就是我们要调用bean对象的逻辑方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getDeclaringClass().getName()+"类的"+method.getName()+"方法!"); return proxy; } /** * factoryBean接口特性再getBean()会调用此方法 * 思路: * 1、我们充分利用factoryBean接口的特性再结合反射就会返回一个代理类充当bean添加到工厂 * */ @Override public Object getObject() throws Exception { Class [] classes = new Class[]{clazz}; Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(),classes,this); return proxy; } @Override public Class<?> getObjectType() { return clazz; } }
测试
AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(Appconfig.class); MapperDao dao = (MapperDao) acc.getBean("mapperDao" ); dao.query(); //注解 @Import(ImplMapperImportBean.class)
原理图:https://www.processon.com/view/link/5d25bc1be4b0ae3317dfc340