basic code structure
bean
bean1
@Slf4j
public class Bean1 {
public Bean1() {
log.info("bean1 constructed");
}
}
bean2
@Slf4j
@Component
public class Bean2 {
public Bean2() {
log.info("bean2 constructed");
}
}
bean3
@Slf4j
@Controller
public class Bean3 {
public Bean3() {
log.info("bean1 constructed");
}
}
config
@Configuration
@ComponentScan("tech.ityoung.spring.a05.component")
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean(initMethod = "init")
public DruidDataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://localhost:3306/world");
druidDataSource.setUsername("root");
druidDataSource.setPassword("22222222");
return druidDataSource;
}
}
mapper
@Mapper
public interface Mapper1 {
}
implement the function of bean factory post processor manually
@Slf4j
public class A05Application {
public static void main(String[] args) throws IOException {
// clean container
GenericApplicationContext context = new GenericApplicationContext();
// only register config
context.registerBean("config", Config.class);
// add support for @ComponentScan @Import @ImportResource @Bean
// context.registerBean(ConfigurationClassPostProcessor.class);
// add import for @Mapper, also add some basic bean post processor like internalCommonAnnotationProcessor, internalAutowiredAnnotationProcessor etc..
// context.registerBean(MapperScannerConfigurer.class, beanDefinition -> beanDefinition.getPropertyValues().addPropertyValue("basePackage", "tech.ityoung.spring.a05.mapper"));
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
String[] basePackages = componentScan.basePackages();
for (String basePackage : basePackages) {
log.warn(basePackage);
// tech.ityoung.a05.component -> classpath*:tech/ityoung/a05/component/**/*.class
String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
log.error(path);
CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
Resource[] resources = context.getResources(path);
for (Resource resource : resources) {
log.info(resource + "");
MetadataReader metadataReader = readerFactory.getMetadataReader(resource);
// get the class name, just like tech.ityoung.spring.a05.component.Bean1
String className = metadataReader.getAnnotationMetadata().getClassName();
log.info(className);
// with @Component annotation
boolean withComponent = metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName());
log.warn("with @Component annotation " + withComponent);
// with annotation from @Component, like @Controller, @Service.
boolean fromComponent = metadataReader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName());
log.warn("with annotation from @Component " + fromComponent);
if (withComponent || fromComponent) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(className).getBeanDefinition();
DefaultListableBeanFactory defaultListableBeanFactory = context.getDefaultListableBeanFactory();
// generate bean name
String beanName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(beanDefinition, defaultListableBeanFactory);
defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
// initiate bean container
context.refresh();
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
log.warn(beanDefinitionName);
}
context.close();
}
}
final output like this picture

package the function into a ComponentScan bean factory post processor

implement BeanFactoryPostProcessor
@Slf4j
public class ComponentScanBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan != null) {
String[] basePackages = componentScan.basePackages();
for (String basePackage : basePackages) {
log.warn(basePackage);
// tech.ityoung.a05.component -> classpath*:tech/ityoung/a05/component/**/*.class
String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
log.error(path);
CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
// Resource[] resources = context.getResources(path);
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
for (Resource resource : resources) {
log.info(resource + "");
MetadataReader metadataReader = null;
metadataReader = readerFactory.getMetadataReader(resource);
// get the class name, just like tech.ityoung.spring.a05.component.Bean1
String className = metadataReader.getAnnotationMetadata().getClassName();
log.info(className);
// with @Component annotation
boolean withComponent = metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName());
log.warn("with @Component annotation " + withComponent);
// with annotation from @Component, like @Controller, @Service.
boolean fromComponent = metadataReader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName());
log.warn("with annotation from @Component " + fromComponent);
if (withComponent || fromComponent) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(className).getBeanDefinition();
if (configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
// generate bean name
String beanName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(beanDefinition, defaultListableBeanFactory);
defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
main
@Slf4j
public class A05Application {
public static void main(String[] args) throws IOException {
// clean container
GenericApplicationContext context = new GenericApplicationContext();
// only register config
context.registerBean("config", Config.class);
// add support for @ComponentScan @Import @ImportResource @Bean
// context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(ComponentScanBeanFactoryPostProcessor.class);
// add import for @Mapper, also add some basic bean post processor like internalCommonAnnotationProcessor, internalAutowiredAnnotationProcessor etc..
// context.registerBean(MapperScannerConfigurer.class, beanDefinition -> beanDefinition.getPropertyValues().addPropertyValue("basePackage", "tech.ityoung.spring.a05.mapper"));
// initiate bean container
context.refresh();
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
log.warn(beanDefinitionName);
}
context.close();
}
}
registering MapperFactoryBean
traditional way
@Bean
public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
MapperFactoryBean<Mapper1> mapperFactoryBean = new MapperFactoryBean<>(Mapper1.class);
mapperFactoryBean.setSqlSessionFactory(sqlSessionFactory);
return mapperFactoryBean;
}
@Bean
public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
MapperFactoryBean<Mapper2> mapperFactoryBean = new MapperFactoryBean<>(Mapper2.class);
mapperFactoryBean.setSqlSessionFactory(sqlSessionFactory);
return mapperFactoryBean;
}
implement the function manually
public class MapperScannerBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
try {
CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
String path = "tech/ityoung/spring/a05/mapper/**/*.class";
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
for (Resource resource : resources) {
MetadataReader metadataReader = readerFactory.getMetadataReader(resource);
ClassMetadata classMetadata = metadataReader.getClassMetadata();
if (classMetadata.isInterface()) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(classMetadata.getClassName())
.getBeanDefinition();
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// only for generating the bean name, otherwise, the bean name should be
AbstractBeanDefinition nameBd = BeanDefinitionBuilder
.genericBeanDefinition(classMetadata.getClassName())
.getBeanDefinition();
String beanName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(nameBd, beanDefinitionRegistry);
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
评论前必须登录!
注册