文章目录
- @ComponentScan + @Componet相关注解
- @Bean
- @Import
- spring.factories
- 总结
- @Configuration和@Component的主要区别?
- @Bean是不是必须和@Configuration一起使用?
- @Import导入配置类有意义?
- 出现异常:java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanDefinitionStoreException
@ComponentScan + @Componet相关注解
@Componet相关注解有@Configuration、@Controller、@Service、@Repository,配合@ComponentScan就能被扫描注册到Spring容器中。
定义我们需要注册的类
@Configuration
public class ForlanConfig {@Beanpublic ForlanBean forlanBean1(){return new ForlanBean();}
}@Component
// @Controller
// @Service
// @Repository
public class ForlanComponent {@Beanpublic ForlanBean forlanBean2(){return new ForlanBean();}
}public class ForlanBean {
}
验证如下:
public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);System.out.println(applicationContext.getBean("forlanConfig"));System.out.println(applicationContext.getBean("forlanComponent"));
}// 输出如下:
cn.forlan.ForlanConfig$$EnhancerBySpringCGLIB$$e43dabb2@1305c126
cn.forlan.ForlanComponent@43af351a
@Bean
前面已经定义好需要注册的类,直接验证即可
验证如下:
public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);System.out.println(applicationContext.getBean("forlanBean1"));System.out.println(applicationContext.getBean("forlanBean2"));
}// 输出如下:
cn.forlan.ForlanBean@64279ab
cn.forlan.ForlanBean@6650a6c
@Import
它可以导入的类有:Component, Configuration, ImportSelector, ImportBeanDefinitionRegistrar, ImportResource
定义我们需要注册的类
public class CaffeineForlanCache {
}public class RedisForlanCache {
}public class ForlanCustomize {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
实现ImportSelector
public class ForlanImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableForlanCache.class.getName());//通过 不同type注入不同的缓存到容器中CacheType cacheType = (CacheType) annotationAttributes.get("cacheType");if(cacheType.equals(CacheType.CAFFEINE)){return new String[]{CaffeineForlanCache.class.getName()};}else{return new String[]{RedisForlanCache.class.getName()};}}
}
实现ImportBeanDefinitionRegistrar
public class ForlanBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(ForlanCustomize.class).addPropertyValue("name", "forlan").getBeanDefinition();registry.registerBeanDefinition("forlanCustomize", beanDefinition);}
}
定义注解导入
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ForlanImportSelector.class, ForlanBeanDefinitionRegistrar.class})
public @interface EnableForlanCache {CacheType cacheType() default CacheType.REDIS;
}
验证如下:
@EnableForlanCache(cacheType = CacheType.CAFFEINE)
public class Application {public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);System.out.println(applicationContext.getBean("forlanBean1"));System.out.println(applicationContext.getBean("forlanBean2"));}
}// 输出如下:
cn.forlan.ForlanCustomize@245cb8df
cn.forlan.CaffeineForlanCache@578c3fd9
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.forlan.RedisForlanCache' available
spring.factories
定义我们需要注册的类
public class ForlanAutoConfiguration {
}
在resources\META-INF下新建spring.factories,填写内容,SpringBoot在启动时,就会自动注入
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.forlan.ForlanAutoConfiguration
验证如下:
public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);System.out.println(applicationContext.getBean(ForlanAutoConfiguration.class));System.out.println(applicationContext.getBean("cn.forlan.ForlanAutoConfiguration"));
}// 输出如下:
cn.forlan.ForlanAutoConfiguration@19d53ab4
cn.forlan.ForlanAutoConfiguration@19d53ab4
注:这种方式的注入的BeanName为路径+类名
总结
总的来说,一共有如下几种方式可以注册bean:
- @ComponentScan + @Componet相关注解
- 使用@Bean注解
- 使用@Import注解
- spring.factories
@Configuration和@Component的主要区别?
使用场景:@Configuration主要用于定义配置类,其中包含了Bean的定义和配置;而@Component适用于任何需要被Spring管理的类。
功能:@Configuration主要用于配置类的定义和初始化Bean;而@Component主要用于组件的自动扫描和注册。
@Bean是不是必须和@Configuration一起使用?
不是的,尽管@Bean注解常常出现在带有@Configuration注解的配置类中,用于定义和初始化Spring容器中的Bean,但它也可以单独使用。@Bean注解的主要作用是告诉Spring框架,被该注解标注的方法将返回一个对象,这个对象需要被注册到Spring容器中。在非配置类中使用@Bean注解,只需要确保该方法能够被Spring扫描到即可。
@Import导入配置类有意义?
总结来说,@Import导入的类本身不是Bean,而是用于扩展Spring容器配置的工具。它可以定义或注册其他的Bean,但你不能直接通过applicationContext.getBean()获取这些导入类的实例。相反,你应该获取它们定义或注册的Bean的实例。它的主要价值在于动态注入Bean。
出现异常:java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanDefinitionStoreException
原因是这个类写的有问题,ForlanImportSelector根本就没有初始化,不是是当前类