本文讲解了在Spring 应用中建立Bean的多种方式,包括自动建立,以及手动建立注入方式,实际开发中能够根据业务场景选择合适的方案。java
使用Spring XML方式配置,该方式用于在纯Spring 应用中,适用于简单的小应用,当应用变得复杂,将会致使XMl配置文件膨胀 ,不利于对象管理。git
<bean id="xxxx" class="xxxx.xxxx"/>
使用@Component,@Service,@Controler,@Repository注解github
这几个注解都是一样的功能,被注解的类将会被Spring 容器建立单例对象。spring
@Component : 侧重于通用的Bean类springboot
@Service:标识该类用于业务逻辑app
@Controler:标识该类为Spring MVC的控制器类ide
@Repository: 标识该类是一个实体类,只有属性和Setter,Getterspring-boot
@Component
public class User{ }
当用于Spring Boot应用时,被注解的类必须在启动类的根路径或者子路径下,不然不会生效。测试
若是不在,可使用@ComponentScan标注扫描的路径。spa
spring xml 也有相关的标签<component-scan />
@ComponentScan(value={"com.microblog.blog","com.microblog.common"}) public class MicroblogBlogApplication { public static void main(String args[]){ SpringApplication.run(MicroblogBlogApplication.class,args); } }
使用@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=com.log.config.UserConfiguration
若是不成功,请引入该依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
这个方式也是建立SpringBoot-starter的方式。
使用注解@Import,也会建立对象并注入容器中
@Import(User.class) public class MicroblogUserWebApplication { public static void main(String args[]) { SpringApplication.run(MicroblogUserWebApplication.class, args); } }
使用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 ...."); } }
selectImports方法的返回值为须要建立Bean的类名称。这里建立User类。
@Slf4j public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { log.info("MyImportSelector selectImports ..."); return new String[]{ User.class.getName()}; } }
beanDefinitionRegistry.registerBeanDefinition用于设置须要建立Bean的类名称。这里建立House类。
@Slf4j public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { log.info("MyImportBeanDefinitionRegistrar registerBeanDefinitions ....."); BeanDefinition beanDefinition = new RootBeanDefinition(House.class.getName()); beanDefinitionRegistry.registerBeanDefinition(House.class.getName(),beanDefinition); } }
这里建立Student类。
@Configuration public class ImportAutoconfiguration { @Bean public Student student(){ return new Student(); } }
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 = context.getBean(User.class); user.run(); Student student = context.getBean(Student.class); student.run(); House house = context.getBean(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 ....
手动注入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;
Location location = new Location();
listableBeanFactory.registerSingleton("location1",location);
}
}
这种方式的应用场景是为接口建立动态代理对象,并向SPRING容器注册。
好比MyBatis中的Mapper接口,Mapper没有实现类,启动时建立动态代理对象,将该对象注册到容器中,使用时只要@Autowired注入便可使用,调用接口方法将会被代理拦截,进而调用相关的SqlSession执行相关的SQL业务逻辑。
能够看如下它的继承体系
DefaultListableBeanFactory 是ConfigurableListableBeanFactory的实现类。是对BeanFactory功能的扩展。
测试代码和以上同样
Location location = context.getBean(Location.class); location.run();
完结。
===========