Spring创建Bean的6种⽅式
前⾔
本⽂讲解了在Spring 应⽤中创建Bean的多种⽅式,包括⾃动创建,以及⼿动创建注⼊⽅式,实际开发中可以根据业务场景选择合适的⽅案。
⽅式1:
使⽤Spring XML⽅式配置,该⽅式⽤于在纯Spring 应⽤中,适⽤于简单的⼩应⽤,当应⽤变得复杂,将会导致XMl配置⽂件膨胀,不利于对象管理。
<bean id="xxxx"  class=""/>
⽅式2:
使⽤@Component,@Service,@Controler,@Repository注解
这⼏个注解都是同样的功能,被注解的类将会被Spring 容器创建单例对象。
@Component : 侧重于通⽤的Bean类
@Service:标识该类⽤于业务逻辑
@Controler:标识该类为Spring MVC的控制器类
@Repository: 标识该类是⼀个实体类,只有属性和Setter,Getter
@Component
public class User{
}
当⽤于Spring Boot应⽤时,被注解的类必须在启动类的根路径或者⼦路径下,否则不会⽣效。
如果不在,可以使⽤@ComponentScan标注扫描的路径。
spring xml 也有相关的标签<component-scan />
@ComponentScan(value={"com.microblog.blog","com.microblogmon"})
public class MicroblogBlogApplication {
public static void main(String args[]){
SpringApplication.run(MicroblogBlogApplication.class,args);
}
}
⽅式3:
使⽤@Bean注解,这种⽅式⽤在Spring Boot 应⽤中。
@Configuration 标识这是⼀个Spring Boot 配置类,其将会扫描该类中是否存在@Bean 注解的⽅法,⽐如如下代码,将会创建User对象并放⼊容器中。
@ConditionalOnBean ⽤于判断存在某个Bean时才会创建User Bean.
这⾥创建的Bean名称默认为⽅法的名称user。也可以@Bean("xxxx")定义。
@Configuration
public class UserConfiguration{
@Bean
    @ConditionalOnBean(Location.class)
public User user(){
return new User();
}
}
Spring boot 还为我们提供了更多类似的注解。
也和⽅式2⼀样,也会存在扫描路径的问题,除了以上的解决⽅式,还有使⽤Spring boot starter 的解决⽅式
在resources下创建如下⽂件。META-INF/spring.factories.
Spring Boot 在启动的时候将会扫描该⽂件,从何获取到配置类UserConfiguration。
spring.factories.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=fig.UserConfiguration
如果不成功,请引⼊该依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
这个⽅式也是创建SpringBoot-starter的⽅式。
⽅式4:
使⽤注解@Import,也会创建对象并注⼊容器中
@Import(User.class)
public class MicroblogUserWebApplication {
适合新手的spring bootpublic static void main(String args[]) {
SpringApplication.run(MicroblogUserWebApplication.class, args);
}
}
⽅式5:
使⽤ImportSelector或者ImportBeanDefinitionRegistrar接⼝,配合@Import实现。
在使⽤⼀些Spring Boot第三⽅组件时,经常会看到@EnableXXX来使能相关的服务,这⾥以⼀个例⼦来实现。
创建测试类
@Slf4j
public class House {
public void run(){
log.info("House  run ....");
}
}
@Slf4j
public class User {
public void run(){
log.info("User  run ....");
}
}
@Slf4j
public class Student {
public void run(){
log.info("Student  run ....");
}
}
实现ImportSelector接⼝
selectImports⽅法的返回值为需要创建Bean的类名称。这⾥创建User类。
@Slf4j
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
log.info("MyImportSelector selectImports ...");
return new String[]{
Name()};
}
}
实现ImportBeanDefinitionRegistrar接⼝
@Slf4j
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {        log.info("MyImportBeanDefinitionRegistrar  registerBeanDefinitions .....");
BeanDefinition beanDefinition =  new RootBeanDefinition(Name());
}
}
创建⼀个配置类
这⾥创建Student类。
@Configuration
public class ImportAutoconfiguration {
@Bean
public Student student(){
return new Student();
}
}
创建EnableImportSelector注解
EnableImportSelector注解上使⽤@Import,引⼊以上的三个类。
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import({MyImportSelector.class,ImportAutoconfiguration.class,MyImportBeanDefinitionRegistrar.class})
public @interface EnableImportSelector {
String value();
}
测试
@EnableImportSelector(value = "xxx")
@SpringBootApplication
public class ImportDemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =  SpringApplication.run(ImportDemoApplication.class, args);
User user =  Bean(User.class);
user.run();
Student student =  Bean(Student.class);
student.run();
House house =  Bean(House.class);
house.run();
}
}
输出,可以看到,三个类User Student House都创建成功,都可从Spring 容器中获取到。
2019-06-20 17:53:39.528  INFO 27255 --- [          main] com.springboot.importselector.pojo.User  : User  run ....
2019-06-20 17:53:39.530  INFO 27255 --- [          main] c.s.importselector.pojo.Student          : Student  run ....
2019-06-20 17:53:39.531  INFO 27255 --- [          main] c.springboot.importselector.pojo.House  : House  run ....
⽅式6
⼿动注⼊Bean容器,有些场景下需要代码动态注⼊,以上⽅式都不适⽤。这时就需要创建对象⼿动注⼊。通过DefaultListableBeanFactory注⼊。
registerSingleton(String beanName,Object object);
这⾥⼿动使⽤new创建了⼀个Location对象。并注⼊容器中。
@Component
public class LocationRegister implements BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory)beanFactory;
    //⽅式1
   // Location location = new Location();
   // isterSingleton(Name(),location);
    //⽅式2
    BeanDefinition locationBeanDefinition = new RootBeanDefinition(Location.class);
    isterBeanDefinition(Name(),locationBeanDefinition);
}
}
这种⽅式的应⽤场景是为接⼝创建动态代理对象,并向SPRING容器注册。
⽐如MyBatis中的Mapper接⼝,Mapper没有实现类,启动时创建动态代理对象,将该对象注册到容器中,使⽤时只要@Autowired注⼊即可使⽤,调⽤接⼝⽅法将会被代理拦截,进⽽调⽤相关的SqlSession执⾏相关的SQL业务逻辑。
可以看以下它的继承体系
DefaultListableBeanFactory 是ConfigurableListableBeanFactory的实现类。是对BeanFactory功能的扩
展。
测试代码和以上⼀样
Location location =  Bean(Location.class);
location.run();
本⽂的相关代码位于
完结。
===========

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。