# 附:Jack老师分享的甜点汇总
# [1] 自定义注解
BeanDefinitionRegistryPostProcessor
当我们想获取BeanDefinitionRegistry对象,来自定义注册过程,可以实现BeanDefinitionRegistryPostProcessor
接口,并重写postProcessBeanDefinitionRegistry
方法。
1、首先自定义一个注解叫
MyService
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
2、创建一个执行类 实现
BeanDefinitionRegistryPostProcessor
接口
@Component
public class BeanDefinitionTest implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//根据BeanDefinitionRegistry对象获创建注解扫描器(Spring源码实现也是通过new 的方式)
//ClassPathBeanDefinitionScanner类就是自定义注解的支撑
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
// 添加自定义注解到注册器中
scanner.addIncludeFilter(new AnnotationTypeFilter(MyService.class));
// 指定注解扫描器的包路径(字符串)
scanner.scan("com.xiangxue.jack.Annotation");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
3、应用自定义注解,这样Spring容器加载的时候就会自动把
MyAnnoClass
类也注册到BeanDefinition
中
@MyService
public class MyAnnoClass {
public String username = "Jack";
}
4、测试类
@Autowired
private MyAnnoClass myAnnoClass;
@Test
public void CostomAnno() {
System.out.println("CostomAnno--->" + myAnnoClass.getUsername());
}
5、执行结果
CostomAnno--->Jack
# [2] 手动实现类注入
BeanDefinitionRegistryPostProcessor
Spring容器中所有注入实例化的类都必须放到BeanDefinition
中,所以也可以实现BeanDefinitionRegistryPostProcessor
接口,并重写postProcessBeanDefinitionRegistry
方法,然后交给Spring 容器来管理。
1、创建一个执行类 实现
BeanDefinitionRegistryPostProcessor
接口
@Component
public class BeanDefinitionTest implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 需要BeanDefinition类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置要注入的bean
genericBeanDefinition.setBeanClass(BeanClass.class);
// 构造方法注入
//genericBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(null);
// 类的属性值需要放到 MutablePropertyValues
MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
// 设置初始化值到propertyValues
propertyValues.addPropertyValue("username","Jack");
// 把bean名称和BeanDefinition对象添加到Map容器中
registry.registerBeanDefinition("beanClass",genericBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
2、测试类
@Test
public void testBean() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.xiangxue.jack");
BeanClass beanClass = (BeanClass)applicationContext.getBean("beanClass");
System.out.println("BeanClass-->" + beanClass.getUsername());
}
3、执行结果
BeanClass-->Jack
警告
如果没有postProcessBeanDefinitionRegistry
方法中手动注册bean,则报错:
- org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'beanClass' available
# [3] 自定义作用域
1、定义一个类继承
BeanFactoryPostProcessor
接口,拿到ConfigurableListableBeanFactory
类的引用,
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 设置自定义的scope 名字,和解析类
beanFactory.registerScope("jackScope",new CustomScope());
}
}
2、定义解析类
public class CustomScope implements Scope {
// 通过 ThreadLocal 来管理bean
private ThreadLocal local = new ThreadLocal();
/*
* 这个方法就是自己管理bean
* */
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if(local.get() != null) {
return local.get();
} else {
//这个方法就是掉createbean方法获得一个实例
Object object = objectFactory.getObject();
local.set(object);
return object;
}
}
}
3、定义入口类
@Component
@Scope("jackScope")
public class CustomScopeBean {
private String username;
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
}
4、测试类
@Test
public void customScopeTest() {
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
if(finalI % 2 == 0) {
System.out.println(Thread.currentThread().getName() + "-->" + applicationContext.getBean("customScopeBean"));
System.out.println(Thread.currentThread().getName() + "-->" + applicationContext.getBean("customScopeBean"));
}
else {
System.out.println(Thread.currentThread().getName() + "-->" + applicationContext.getBean("customScopeBean"));
}
}).start();
}
}
5、执行结果,可见同一个线程执行两次的结果hash一致
Thread-5-->com.xiangxue.jack.scope.CustomScopeBean@132d6fa
Thread-1-->com.xiangxue.jack.scope.CustomScopeBean@b4a3ea2
Thread-8-->com.xiangxue.jack.scope.CustomScopeBean@191edca8
Thread-6-->com.xiangxue.jack.scope.CustomScopeBean@32280ef5
Thread-7-->com.xiangxue.jack.scope.CustomScopeBean@7fbdeb7d
Thread-3-->com.xiangxue.jack.scope.CustomScopeBean@1601fd2a
Thread-9-->com.xiangxue.jack.scope.CustomScopeBean@399e5f47
Thread-10-->com.xiangxue.jack.scope.CustomScopeBean@283b28be
Thread-3-->com.xiangxue.jack.scope.CustomScopeBean@1601fd2a
Thread-7-->com.xiangxue.jack.scope.CustomScopeBean@7fbdeb7d
Thread-1-->com.xiangxue.jack.scope.CustomScopeBean@b4a3ea2
Thread-4-->com.xiangxue.jack.scope.CustomScopeBean@44d305aa
Thread-5-->com.xiangxue.jack.scope.CustomScopeBean@132d6fa
Thread-2-->com.xiangxue.jack.scope.CustomScopeBean@30fd9718
Thread-9-->com.xiangxue.jack.scope.CustomScopeBean@399e5f47
# [4] 自定义类让所有依赖注入失效
定义一个神奇的类,实现
InstantiationAwareBeanPostProcessor
接口
//@Service
public class InstantiationAwareBeanPostProcessorDemo implements InstantiationAwareBeanPostProcessor {
@Override
// 设置返回false,Spring依赖注入的时候会直接 break ,不会继续往下走
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return false;
}
}
分析原因:Spring 依赖注入 populateBean() 方法中有个业务逻辑可以让所有注入失效。
//这里很有意思,写接口可以让所有类都不能依赖注入
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
//是否需要DI,依赖注入
continueWithPropertyPopulation = false;
break;
}
}
}
}