# 附: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;
					}
				}
			}
		}