本文講解了在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();
完結。
===========