spring boot能夠根據依賴的jar包自動配置spring boot的應用,例如: 如果類路徑中存在
DispatcherServlet
類,就會自動配置springMvc相關的Bean。spring boot的自動裝配來源于spring的裝配,功能也是随時spring的不斷更新不斷完善的,spring boot正是在spring的基礎上實作的自動裝配。
spring模式注解裝配
模式注解介紹
模式注解是應用程式中用來标注元件的注解,例如:
@Repository
是spring架構中用來标注資料通路對象(DAO)的注解。
@Component
是用來标注被spring管理的通用的元件,
@Component
标注的類都可以被spring容器掃描到。并且任何标注
@Component
元注解的的注解也能被spring掃描到,比如
@Service
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
下面是spring中常用的模式注解
spring注解 | 使用場景 | 起始版本 |
---|---|---|
| 資料倉儲模式注解 | 2.0 |
| 通用元件模式注解 | 2.5 |
| 服務模式注解 | 2.5 |
| Web 控制器模式注解 | 2.5 |
| 配置類模式注解 | 3.0 |
裝配方式
spring中通過配置掃描的包 ,就能掃描到注解的元件,有兩種配置的方式:
XML配置
通過
context:component-scan
标簽的
base-package
屬性,配置需要掃描的包
注解方式裝配
自定義模式注解
可以通過在自定義注解上加上元注解的方式,自定義模式注解。例如:
@UserRepository
注解上加上元注解
@Repository
,這樣
@UserRepository
也是模式注解了。這是由于注解具有派生性的特點,
@UserRepository
派生至
@Repository
,
@Repository
派生至
@Component
。
@Repository
public @interface UserRepository {
String value() default "";
}
spring @Enable子產品裝配
spring3.1開始支援
@Enable
子產品裝配,所謂子產品是指,把具有相同功能的元件組合在一起,引入到項目中。比如
@EnableWebMvc
注解,就是把spring MVC相關的配置引入到項目中,而不需要其他配置,友善使用spring MVC。這種裝配方式是通過
@Import
注解引入其他配置類來實作的,
@EnableWebMvc
通過引入
DelegatingWebMvcConfiguration
配置類,實作spring MVC的自動配置。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
引入的配置類有兩種實作形式,一種是直接使用模式注解
@Configuration
的類,另一種是實作
ImportSelector
接口的
selectImports
方法,來引入配置類。
注解方式
@EnableWebMvc
就是這種實作方式。
下面列舉
User
子產品的裝配來具體說明實作的方式。可以看出
EnableUserConfig
是通過直接導入
UserConfiguration
來裝配
User
子產品的。
UserConfiguration
配置類
UserConfiguration
@Configuration
public class UserConfiguration {
@Bean
public UserService userService(UserDao userDao){
return new UserService(userDao);
@Bean
public UserDao userDao() {
return new UserDao();
}
}
EnableUserConfig
注解
EnableUserConfig
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfiguration.class)
public @interface EnableUserConfig {
}
使用啟動類
@EnableUserConfig
public class EnableUserConfigBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(EnableUserConfigBootstrap.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println("EnableUserConfigBootstrap.main" + userService.findBId(1));
context.close();
}
}
ImportSelector
接口方式
ImportSelector
spring中的
EnableCaching
就是這種實作方式。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
}
下面列舉
User
子產品的裝配來具體說明實作的方式。這種方式是通過
UserConfigurationSelector
來引入
User
的配置類
UserConfiguration
。
UserConfigurationSelector
類用來導入 UserConfiguration
配置
UserConfigurationSelector
UserConfiguration
public class UserConfigurationSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {UserConfiguration.class.getName()};
}
}
EnableUserSelector
注解
EnableUserSelector
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfigurationSelector.class)
public @interface EnableUserSelector {
}
使用啟動類
@EnableUserSelector
public class EnableUserSelectorBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(EnableUserSelectorBootstrap.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println("EnableUserSelectorBootstrap.main" + userService.findBId(1));
context.close();
}
}
spring條件裝配
spring3.1開始,spring引入了
@Profile
注解,可以根據環境
Environment
的不同引入不同的配置。spring4.0開始,
Conditional
注解可以更靈活的根據不同條件引入不同的配置。
@Profile
注解方式的條件裝配
@Profile
使用
User
子產品的不能
dao
裝配來說明
@Profile
的條件裝配。
UserProfileConfiguration
配置
UserProfileConfiguration
@Configuration
public class UserProfileConfiguration {
@Bean
public UserServiceForProfile userServiceForProfile(IUserDao userDao) {
return new UserServiceForProfile(userDao);
}
@Bean
@Profile("mysql")
public IUserDao userMysqlDao() {
return new UserMysqlDao();
}
@Bean
@Profile("oracle")
public IUserDao userOracleDao() {
return new UserOracleDao();
}
}
Environment
激活使用
Environment
通過
context.getEnvironment().setActiveProfiles("oracle");
的方式,來激活不同的
Profile
public class ProfileBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
context.register(UserProfileConfiguration.class);
context.getEnvironment().setActiveProfiles("oracle");
context.refresh();
UserServiceForProfile userService = context.getBean("userServiceForProfile",
UserServiceForProfile.class);
System.out.println("ProfileBootstrap.main" + userService.findBId(1));
context.close();
}
}
@Conditional
注解方式的條件裝配
@Conditional
@Conditional
注解方式,通過引入實作
Condition
接口的類,來判斷條件是否成立,進而确定是否引入某個元件。這個類是通過實作
matches
方法來判斷條件是否成立。spring4.0開始,由于引入了
@Conditional
注解,
Profile
也是通過
@Conditional
來實作的。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}
spring boot中大量使用了
@Conditional
注解的方式,來自動裝配不同的元件。
@ConditionalOnClass
用來表示類路徑存在某些類時加載;
@ConditionalOnMissingBean
用來判斷某些類的執行個體不存在時加載;
ConditionalOnWebApplication
用來判斷某種應用類型時加載。例如
webmvc
的自動加載配置
WebMvcAutoConfiguration
:
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}
下面的例子是根據系統變量的值來決定是否裝配
UserDao
OnSystemPropertyCondition
實作 Condition
接口的 matches
方法,用來判斷是否符合條件
OnSystemPropertyCondition
Condition
matches
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
String propertyName = String.valueOf(annotationAttributes.get("name"));
String propertyValue = String.valueOf(annotationAttributes.get("value"));
String systemPropertyValue = System.getProperty(propertyName);
return propertyValue.equals(systemPropertyValue);
}
}
ConditionalOnSystemProperty
注解
ConditionalOnSystemProperty
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
String name();
String value();
}
啟動類
public class ConditionalOnSystemPropertyBootstrap {
@ConditionalOnSystemProperty(name = "user.name", value = "Administrator")
@Bean
public UserDao userDao() {
return new UserDao();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(ConditionalOnSystemPropertyBootstrap.class);
UserDao userDao = context.getBean("userDao", UserDao.class);
System.out.println("ConditionalOnSystemPropertyBootstrap.main" + userDao.findBId(1));
context.close();
}
}
如果 value
指定錯誤,就會報錯:
value
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userDao' available
spring boot自動裝配
spring boot的自動裝配結合了上面介紹的spring模式注解、@Enable子產品裝配和條件裝配。另外,spring boot自身還使用了工廠加載機制,用
SpringFactoriesLoader
來裝載配置類。
實作方法
- 實作自動裝配的類
- 在
檔案中配置第一步中的類META-INF/spring.factories
-
@EnableAutoConfiguration
注解激活配置
下面以
子產品的自動裝配為例,來介紹具體的實作步驟User
實作裝配類 UserAutoConfiguration
UserAutoConfiguration
這裡用到了前面介紹的@Enable子產品裝配和條件裝配
@EnableUserSelector
@ConditionalOnSystemProperty(name = "user.name", value = "Administrator")
public class UserAutoConfiguration {
}
在 META-INF/spring.factories
檔案中添加配置
META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.laoliangcode.configuration.UserAutoConfiguration
啟動類中添加 @EnableAutoConfiguration
注解激活配置
@EnableAutoConfiguration
@EnableAutoConfiguration
public class AutoConfigurationBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(AutoConfigurationBootstrap.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println("AutoConfigurationBootstrap.main" + userService.findBId(1));
context.close();
}
}
如果在第一步中,讓條件裝配不符合條件,就會報錯:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userService' available
文中詳細代碼在github上
https://github.com/laoliangcode/springboot-demo/tree/master/autoconfigure