文章目录
- FactoryBean
- @Indexed 原理
- Spring代理的特点
- @Value 装配底层
- @Autowired 装配底层
- 事件监听器
- 模拟事件发布器
FactoryBean
FactoryBean是一个Factory对象,用于生成其他bean示例。当一个bean实现FactoryBean接口后,Spring容器调用其getObject方法返回该工厂所生成的bean,而不是该FactoryBean本身。但是工厂生成的产品对象只能说是一部分受到Spring容器的管理,我们来看看下面的例子:
我们把一个Bean1通过工厂Bean的方法纳入Spring管理,看看结果:
Bean1:
public class Bean1 implements BeanFactoryAware {private static final Logger log = LoggerFactory.getLogger(Bean1.class);private Bean2 bean2;@Autowiredpublic void setBean2(Bean2 bean2) {log.debug("setBean2({})", bean2);this.bean2 = bean2;}public Bean2 getBean2() {return bean2;}@PostConstructpublic void init() {log.debug("init");}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {log.debug("setBeanFactory({})", beanFactory);}
}
Bean1的工厂类:
@Component("bean1")
public class Bean1FactoryBean implements FactoryBean<Bean1> {private static final Logger log = LoggerFactory.getLogger(Bean1FactoryBean.class);// 决定了根据【类型】获取或依赖注入能否成功@Overridepublic Class<?> getObjectType() {return Bean1.class;}// 决定了 getObject() 方法被调用一次还是多次@Overridepublic boolean isSingleton() {return true;}@Overridepublic Bean1 getObject() throws Exception {Bean1 bean1 = new Bean1();log.debug("create bean: {}", bean1);return bean1;}
}
Bean后处理器:
@Component
public class Bean1PostProcessor implements BeanPostProcessor {private static final Logger log = LoggerFactory.getLogger(Bean1PostProcessor.class);@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("bean1") && bean instanceof Bean1) {log.debug("before [{}] init", beanName);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("bean1") && bean instanceof Bean1) {log.debug("after [{}] init", beanName);}return bean;}
}
测试类:
@ComponentScan
public class A43 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A43.class);Bean1 bean1 = (Bean1) context.getBean("bean1");Bean1 bean2 = (Bean1) context.getBean("bean1");Bean1 bean3 = (Bean1) context.getBean("bean1");//因为工厂isSingleton方法返回的true,所以是单例模式System.out.println(bean1);System.out.println(bean2);System.out.println(bean3);//如果想通过类型获取,那么工厂中的getObjectType方法就一定要返回正确的值System.out.println(context.getBean(Bean1.class));//两种获取工厂bean的方法System.out.println(context.getBean(Bean1FactoryBean.class));System.out.println(context.getBean("&bean1"));context.close();}
结果:
总结💡:
- 它的作用是用制造创建过程较为复杂的产品, 如 SqlSessionFactory, 但 @Bean 已具备等价功能
- 使用上较为古怪, 一不留神就会用错
- 被 FactoryBean 创建的产品
- 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会走
- 唯有后初始化的流程会走, 也就是产品可以被代理增强
- 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个 factoryBeanObjectCache 成员中
- 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象。当然我们也可以通过工厂类型去拿工厂对象。
- 被 FactoryBean 创建的产品
@Indexed 原理
💡
- 在编译时就根据 @Indexed 生成 META-INF/spring.components 文件
- 扫描时(二选一)
- 如果发现 META-INF/spring.components 存在, 以它为准加载 bean definition
- 否则, 会遍历包下所有 class 资源 (包括 jar 内的)
- 解决的问题:在编译期就找到 @Component 组件,节省运行期间扫描 @Component 的时间
Spring代理的特点
我们看一段代码:
@Component
public class Bean1 {private static final Logger log = LoggerFactory.getLogger(Bean1.class);protected Bean2 bean2;protected boolean initialized;@Autowiredpublic void setBean2(Bean2 bean2) {log.debug("setBean2(Bean2 bean2)");this.bean2 = bean2;}@PostConstructpublic void init() {log.debug("init");initialized = true;}public Bean2 getBean2() {log.debug("getBean2()");return bean2;}public boolean isInitialized() {log.debug("isInitialized()");return initialized;}
}
增强:
@Aspect
@Component
public class MyAspect {// 故意对所有方法增强@Before("execution(* com.itheima.a45.Bean1.*(..))")public void before() {System.out.println("before");}
}
测试类:
从这里我们可以看出来依赖注入和初始化影响的是原始对象
我们再来看看代理与目标的成员变量情况:
public static void showProxyAndTarget(Bean1 proxy) throws Exception {System.out.println(">>>>> 代理中的成员变量");System.out.println("\tinitialized=" + proxy.initialized);System.out.println("\tbean2=" + proxy.bean2);if (proxy instanceof Advised advised) {System.out.println(">>>>> 目标中的成员变量");Bean1 target = (Bean1) advised.getTargetSource().getTarget();System.out.println("\tinitialized=" + target.initialized);System.out.println("\tbean2=" + target.bean2);}}
所以说代理与目标是两个对象,二者成员变量并不共用数据。我们平时是使用的方法去获取成员变量,方法虽然被增强,但其中还是会调用原方法,所以获取的就是目标对象中的成员变量。这也给我们一种提示我们想要走代理增强就必须走方法,不能走成员。
-
spring 代理的设计特点
-
依赖注入和初始化影响的是原始对象
- 因此 cglib 不能用 MethodProxy.invokeSuper()
-
代理与目标是两个对象,二者成员变量并不共用数据
-
-
static 方法、final 方法、private 方法均无法增强
- 进一步理解代理增强基于方法重写,这三种情况是无法被增强的
@Value 装配底层
- 查看需要的类型是否为 Optional,是,则进行封装(非延迟),否则向下走
- 查看需要的类型是否为 ObjectFactory 或 ObjectProvider,是,则进行封装(延迟),否则向下走
- 查看需要的类型(成员或参数)上是否用 @Lazy 修饰,是,则返回代理,否则向下走
- 解析 @Value 的值
- 如果需要的值是字符串,先解析 ${ },再解析 #{ }
- 不是字符串,需要用 TypeConverter 转换
- 看需要的类型是否为 Stream、Array、Collection、Map,是,则按集合处理,否则向下走
- 在 BeanFactory 的 resolvableDependencies 中找有没有类型合适的对象注入,没有向下走
- 在 BeanFactory 及父工厂中找类型匹配的 bean 进行筛选,筛选时会考虑 @Qualifier 及泛型
- 结果个数为 0 抛出 NoSuchBeanDefinitionException 异常
- 如果结果 > 1,再根据 @Primary 进行筛选
- 如果结果仍 > 1,再根据成员名或变量名进行筛选
- 结果仍 > 1,抛出 NoUniqueBeanDefinitionException 异常
示例代码:
@Configuration
@SuppressWarnings("all")
public class A46 {public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A46.class);DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();resolver.setBeanFactory(beanFactory);// test1(context, resolver, Bean1.class.getDeclaredField("home"));
// test2(context, resolver, Bean1.class.getDeclaredField("age"));
// test3(context, resolver, Bean2.class.getDeclaredField("bean3"));test3(context, resolver, Bean4.class.getDeclaredField("value"));}private static void test3(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {DependencyDescriptor dd1 = new DependencyDescriptor(field, false);// 获取 @Value 的内容String value = resolver.getSuggestedValue(dd1).toString();System.out.println(value);// 解析 ${}value = context.getEnvironment().resolvePlaceholders(value);System.out.println(value);System.out.println(value.getClass());// 解析 #{} @bean3Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));// 类型转换Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());System.out.println(result);}private static void test2(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {DependencyDescriptor dd1 = new DependencyDescriptor(field, false);// 获取 @Value 的内容String value = resolver.getSuggestedValue(dd1).toString();System.out.println(value);// 解析 ${}value = context.getEnvironment().resolvePlaceholders(value);System.out.println(value);System.out.println(value.getClass());Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value, dd1.getDependencyType());System.out.println(age.getClass());}private static void test1(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {DependencyDescriptor dd1 = new DependencyDescriptor(field, false);// 获取 @Value 的内容String value = resolver.getSuggestedValue(dd1).toString();System.out.println(value);// 解析 ${}value = context.getEnvironment().resolvePlaceholders(value);System.out.println(value);}public class Bean1 {@Value("${JAVA_HOME}")private String home;@Value("18")private int age;}public class Bean2 {@Value("#{@bean3}") // SpringEL #{SpEL}private Bean3 bean3;}@Component("bean3")public class Bean3 {}static class Bean4 {@Value("#{'hello, ' + '${JAVA_HOME}'}")private String value;}
}
重点:
- ${ }对应的解析方法:context.getEnvironment().resolvePlaceholders
- #{ } 对应的解析方法:context.getBeanFactory().getBeanExpressionResolver().evaluate
- ContextAnnotationAutowireCandidateResolver 作用之一,获取 @Value 的值
@Autowired 装配底层
收获💡
- @Autowired 本质上是根据成员变量或方法参数的类型进行装配
- 如果待装配类型是 Optional,需要根据 Optional 泛型找到 bean,再封装为 Optional 对象装配
- 如果待装配的类型是 ObjectFactory,需要根据 ObjectFactory 泛型创建 ObjectFactory 对象装配
- 此方法可以延迟 bean 的获取
- 如果待装配的成员变量或方法参数上用 @Lazy 标注,会创建代理对象装配
- 此方法可以延迟真实 bean 的获取
- 被装配的代理不作为 bean
- 如果待装配类型是数组,需要获取数组元素类型,根据此类型找到多个 bean 进行装配
- 如果待装配类型是 Collection 或其子接口,需要获取 Collection 泛型,根据此类型找到多个 bean
- 如果待装配类型是 ApplicationContext 等特殊类型
- 会在 BeanFactory 的 resolvableDependencies 成员按类型查找装配
- resolvableDependencies 是 map 集合,key 是特殊类型,value 是其对应对象
- 不能直接根据 key 进行查找,而是用 isAssignableFrom 逐一尝试右边类型是否可以被赋值给左边的 key 类型
- 如果待装配类型有泛型参数
- 需要利用 ContextAnnotationAutowireCandidateResolver 按泛型参数类型筛选
- 如果待装配类型有 @Qualifier
- 需要利用 ContextAnnotationAutowireCandidateResolver 按注解提供的 bean 名称筛选
- 有 @Primary 标注的 @Component 或 @Bean 的处理
- 与成员变量名或方法参数名同名 bean 的处理
事件监听器
事件监听器的两种方式
- 实现 ApplicationListener 接口
- 根据接口泛型确定事件类型
- @EventListener 标注监听方法
- 根据监听器方法参数确定事件类型
- 解析时机:在 SmartInitializingSingleton(所有单例初始化完成后),解析每个单例 bean
示例代码:
实现 ApplicationListener 接口:
// 事件解耦例子
@Configuration
public class A48_1 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_1.class);context.getBean(MyService.class).doBusiness();context.close();}static class MyEvent extends ApplicationEvent {public MyEvent(Object source) {super(source);}}@Componentstatic class MyService {private static final Logger log = LoggerFactory.getLogger(MyService.class);@Autowiredprivate ApplicationEventPublisher publisher; // applicationContextpublic void doBusiness() {log.debug("主线业务");// 主线业务完成后需要做一些支线业务,下面是问题代码publisher.publishEvent(new MyEvent("MyService.doBusiness()"));}}@Componentstatic class SmsApplicationListener implements ApplicationListener<MyEvent> {private static final Logger log = LoggerFactory.getLogger(SmsApplicationListener.class);@Overridepublic void onApplicationEvent(MyEvent event) {log.debug("发送短信");}}@Componentstatic class EmailApplicationListener implements ApplicationListener<MyEvent> {private static final Logger log = LoggerFactory.getLogger(EmailApplicationListener.class);@Overridepublic void onApplicationEvent(MyEvent event) {log.debug("发送邮件");}}}
使用@EventListener:
@Configuration
public class A48_2 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_2.class);context.getBean(MyService.class).doBusiness();context.close();}static class MyEvent extends ApplicationEvent {public MyEvent(Object source) {super(source);}}@Componentstatic class MyService {private static final Logger log = LoggerFactory.getLogger(MyService.class);@Autowiredprivate ApplicationEventPublisher publisher; // applicationContextpublic void doBusiness() {log.debug("主线业务");// 主线业务完成后需要做一些支线业务,下面是问题代码publisher.publishEvent(new MyEvent("MyService.doBusiness()"));}}@Componentstatic class SmsService {private static final Logger log = LoggerFactory.getLogger(SmsService.class);@EventListenerpublic void listener(MyEvent myEvent) {log.debug("发送短信");}}@Componentstatic class EmailService {private static final Logger log = LoggerFactory.getLogger(EmailService.class);@EventListenerpublic void listener(MyEvent myEvent) {log.debug("发送邮件");}}//模拟多线程 @Beanpublic ThreadPoolTaskExecutor executor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(3);executor.setMaxPoolSize(10);executor.setQueueCapacity(100);return executor;}@Beanpublic SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();multicaster.setTaskExecutor(executor);return multicaster;}}
模拟事件发布器
@Beanpublic ApplicationEventMulticaster applicationEventMulticaster(ConfigurableApplicationContext context, ThreadPoolTaskExecutor executor) {return new AbstractApplicationEventMulticaster() {private List<GenericApplicationListener> listeners = new ArrayList<>();// 收集监听器public void addApplicationListenerBean(String name) {ApplicationListener listener = context.getBean(name, ApplicationListener.class);System.out.println(listener);// 获取该监听器支持的事件类型ResolvableType type = ResolvableType.forClass(listener.getClass()).getInterfaces()[0].getGeneric();System.out.println(type);// 将原始的 listener 封装为支持事件类型检查的 listenerGenericApplicationListener genericApplicationListener = new GenericApplicationListener() {// 是否支持某事件类型 真实的事件类型public boolean supportsEventType(ResolvableType eventType) {return type.isAssignableFrom(eventType);}public void onApplicationEvent(ApplicationEvent event) {executor.submit(() -> listener.onApplicationEvent(event));}};listeners.add(genericApplicationListener);}// 发布事件public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {for (GenericApplicationListener listener : listeners) {if (listener.supportsEventType(ResolvableType.forClass(event.getClass()))) {listener.onApplicationEvent(event);}}}};}
为了只实现两个核心方法,我们创建了一个AbstractApplicationEventMulticaster对ApplicationEventMulticaster接口进行了空实现,并定义为抽象类:
事件发布器模拟实现
- addApplicationListenerBean 负责收集容器中的监听器
- 监听器会统一转换为 GenericApplicationListener 对象,以支持判断事件类型
- multicastEvent 遍历监听器集合,发布事件
- 发布前先通过 GenericApplicationListener.supportsEventType 判断支持该事件类型才发事件
- 可以利用线程池进行异步发事件优化
- 如果发送的事件对象不是 ApplicationEvent 类型,Spring 会把它包装为 PayloadApplicationEvent 并用泛型技术解析事件对象的原始类型