1.1、BeanFactoryPostProcessor接口
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置’order’属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息,
1.2、实现 BeanFactoryPostProcessor 调用 postProcessBeanFactory 方法 修改 BeanDefinition 信息(以下方法只关注 postProcessBeanFactory,其他方法不实现会报错,不得已都写上了 )
/**
* 用于Spring动态注入自定义接口
*
* @author lichuang
*/
@Component
public class ServiceBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, ApplicationContextAware {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//这里一般我们是通过反射获取需要代理的接口的clazz列表
//比如判断包下面的类,或者通过某注解标注的类等等
Set<Class<?>> beanClazzs = scannerPackages("com.example.yuanmayuedu.service");
for (Class beanClazz : beanClazzs) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz);
GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
//在这里,我们可以给该对象的属性注入对应的实例。
//比如mybatis,就在这里注入了dataSource和sqlSessionFactory,
// 注意,如果采用definition.getPropertyValues()方式的话,
// 类似definition.getPropertyValues().add("interfaceType", beanClazz);
// 则要求在FactoryBean(本应用中即ServiceFactory)提供setter方法,否则会注入失败
// 如果采用definition.getConstructorArgumentValues(),
// 则FactoryBean中需要提供包含该属性的构造方法,否则会注入失败
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClazz);
//注意,这里的BeanClass是生成Bean实例的工厂,不是Bean本身。
// FactoryBean是一种特殊的Bean,其返回的对象不是指定类的一个实例,
// 其返回的是该工厂Bean的getObject方法所返回的对象。
definition.setBeanClass(ServiceFactory.class);
//这里采用的是byType方式注入,类似的还有byName等
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_NAME);
registry.registerBeanDefinition(beanClazz.getSimpleName(), definition);
}
}
private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
private MetadataReaderFactory metadataReaderFactory;
/**
* 根据包路径获取包及子包下的所有类
*
* @param basePackage basePackage
* @return Set<Class < ?>> Set<Class<?>>
*/
private Set<Class<?>> scannerPackages(String basePackage) {
Set<Class<?>> set = new LinkedHashSet<>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN;
try {
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
Class<?> clazz;
try {
clazz = Class.forName(className);
set.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return set;
}
protected String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(this.getEnvironment().resolveRequiredPlaceholders(basePackage));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//在此处获取到bean 定义 并修改bean定义(仅以 setLazyInit为例)
// beanDefinition 详细属性及含义见
BeanDefinition beanDefinition= beanFactory.getBeanDefinition("test");
beanDefinition.setLazyInit(true);
System.out.println(beanDefinition);
}
private ResourcePatternResolver resourcePatternResolver;
private ApplicationContext applicationContext;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private Environment getEnvironment() {
return applicationContext.getEnvironment();
}
}
2.1、BeanPostProcessor接口
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
BeanPostProcessor,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。这里说的初始化方法,指的是下面两种:
1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
2)在bean定义的时候,通过init-method设置的方法
注意:BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后。
2.2、自己实现 BeanPostProcessor 对 在 bean 初始化前后增加自己的逻辑
完整写法见:BeanPostProcessor 介绍及使用
@Component
public class ServiceBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof TestService) {
System.out.println("-----------------------------");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
//标识Spring-generated proxies
enhancer.setInterfaces(new Class[]{TestService.class});
//设置增强
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy
methodProxy) throws Throwable {
System.out.println("开始事务。。。");
Object obj;
try {
obj = methodProxy.invokeSuper(o, objects);// 推荐写法
System.out.println(obj);
} catch (Exception e) {
System.out.println("回滚事务。。。");
throw e;
}
System.out.println("结束事务。。。");
return obj;
}
});
return enhancer.create();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
}