JavaConfig與常見Annotation(必知必會(huì)系列)
文章目錄
JavaConfig
@ComponentScan
@Import
@Conditional
@ConfigurationProperties與@EnableConfigurationProperties
組合注解
總結(jié)
上一篇我們介紹了 Spring中Bean的生命周期,這一篇我們接著學(xué)習(xí)在Spring Boot中的一些常用注解。
JavaConfig
說注解之前,我們先了解下JavaConfig。在注解方式實(shí)例化Bean之前,我們都是通過XML來配置Bean以及其依賴關(guān)系的,造成了項(xiàng)目中有大量的XML文件,使項(xiàng)目變得復(fù)雜,不便于維護(hù)。所以JavaConfig
就應(yīng)運(yùn)而生了,JavaConfig是Spring的一個(gè)子項(xiàng)目。它基于Java代碼和Annotation注解來描述Bean之間的依賴綁定關(guān)系。
例如:teacherService類,通過XML配置如下:
<bean id="teacherService" class="com.jay.spring.configuration.TeacherServiceImpl"></bean>
通過JavaConfig 配置就是這樣的:
@Configuration
public class TeacherConfiguration {
@Bean
public TeacherService teacherService(){
return new TeacherServiceImpl();
}
}
@Configuration 注解標(biāo)注在類上,相當(dāng)于把該類作為Spring的XML配置文件中的,其作用為:配置Spring容器,需要注意的是:
@Configuration不可以是final類型;
@Configuration 不可以是匿名類
嵌套的Configuration必須是靜態(tài)類。
@Bean 注解標(biāo)注方法上(返回某個(gè)實(shí)例的方法),等價(jià)于Spring的XML配置文件中的<bean>,作用是注冊bean對(duì)象,對(duì)象實(shí)例的名字默認(rèn)是方法名。我們也可以通過name 屬性來指定實(shí)例名。
@Bean 注解默認(rèn)作用域?yàn)閱卫齭ingleton 作用域,可通過@Scope(”prototype“)設(shè)置為原型作用域
既然@Bean的作用是注冊bean對(duì)象,那么完全可以使用@Component、@Controller、@Service、@Ripository等注解注冊bean,當(dāng)然需要配置@ComponentScan注解進(jìn)行自動(dòng)掃描。
@ComponentScan
@ComponentScan注解對(duì)應(yīng)Spring的XML配置文件中的context:component-scan/
表示啟動(dòng)組件掃描,Spring會(huì)自動(dòng)掃描所有通過注解配置的bean,然后將其注冊到IOC容器中,我們可以通過basePackages屬性來指定@ComponentScan自動(dòng)掃描的范圍,如果不指定,則默認(rèn)從聲明@ComponentScan所在類的package進(jìn)行掃描,正是因?yàn)槿绱?,SpringBoot的啟動(dòng)類都是默認(rèn)在/src/main/java下。
@Import
@Import 注解用于導(dǎo)入配置類,應(yīng)用場景就是一個(gè)配置類中的一個(gè)Bean依賴于另一個(gè)配置類中的一個(gè)Bean。例如:下面有一個(gè)TeacherConfiguration配置類。這個(gè)類里定義了一個(gè)TeacherService的實(shí)例。
@Configuration
public class TeacherConfiguration {
@Bean
public TeacherService teacherService(){
return new TeacherServiceImpl();
}
}
還有一個(gè)StudentConfiguration配置類,這個(gè)配置類中定義的StudentService的實(shí)例需要依賴TeacherService對(duì)象。所以我們在StudentConfiguration中將TeacherConfiguration引入,如下所示:
@Configuration
//可以同時(shí)導(dǎo)入多個(gè)配置文件,比如:@Import({A.class,B.class})
@Import(TeacherConfiguration.class)
public class StudentConfiguration {
@Bean
public StudentService studentService(TeacherService teacherService) {
return new StudentServiceImpl(teacherService);
}
}
StudentServiceImpl 類中如下所示:
public class StudentServiceImpl implements StudentService {
private TeacherService teacherService;
public StudentServiceImpl(TeacherService teacherService) {
this.teacherService = teacherService;
}
}
@Import 注解支持導(dǎo)入普通java類,并將其聲明成一個(gè)Bean,主要用于將多個(gè)分散的JavaConfig配置類融合成一個(gè)更大的config類。
@Import 注解在4.2之前只支持導(dǎo)入配置類。
在4.2之后@Import注解支持導(dǎo)入普通的java類,并將其聲明成一個(gè)Bean。
@Import三種使用方式:
直接導(dǎo)入普通的Java類。
配合自定義的ImportSelector使用。
配合ImportBeanDefinitionRegistrar使用。
@Conditional
@Conditional注解表示滿足某種條件之后才開始初始化一個(gè)Bean或者啟動(dòng)某些配置,它一般用在由@Component、@Service、@Configuration等注解標(biāo)識(shí)的類上面,或者由@Bean標(biāo)記的方法上。如果一個(gè)@Configuration類標(biāo)記了
@Conditional,則該類中所有標(biāo)識(shí)了@Bean的方法和@Import注解導(dǎo)入的相關(guān)類將遵從這些條件。
如果我們需要自定義自己的條件類,所要做的就是實(shí)現(xiàn)Condtition接口,并覆蓋它的matches()方法。
下面舉栗子說明下,
public class JdbcTemplateCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
context.getClassLoader().loadClass(“org.springframework.jdbc.core.JdbcTemplate”);
return true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return false;
}
}
當(dāng)你用Java來聲明Bean的時(shí)候,可以使用這個(gè)自定義條件類:
@Conditional(JdbcTemplateCondition.class)
@Service
public class JdbcDemoService {
}
這個(gè)栗子中只有當(dāng)JdbcTemplateCondition類的條件成立時(shí)才會(huì)創(chuàng)建JdbcDemoService這個(gè)Bean,也就是說JdbcDemoService這個(gè)Bean的創(chuàng)建條件是classpath里面包括JdbcTemplate,否則這個(gè)bean的聲明就會(huì)被忽略掉。
在SpringBoot中還有一些有意思的條件注解。
@ConfigurationProperties與@EnableConfigurationProperties
當(dāng)某些屬性的值需要配置的時(shí)候,我們一般會(huì)在applcation.properties文件中新建配置項(xiàng),然后通過@Value注解來獲取配置項(xiàng),比如下面配置數(shù)據(jù)源的代碼。
// jdbc config
jdbc.mysql.url=jdbc:mysql://localhost:3306/category
jdbc.mysql.username=root
jdbc.mysql.password=123456
//配置數(shù)據(jù)源
@Configuration
public class DataSouceConfiguration {
@Value(“jdbc.mysql.url”)
public String url;
@Value(“jdbc.mysql.username”)
public String user;
@Value(“jdbc.mysql.password”)
public String password;
@Bean
public DataSource dataSource() {
DataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(password);
return ds;
}
}
如果配置比較多的話,是用@Value來獲取注解就比較low了,代碼也不美觀。沒關(guān)系,我們還有個(gè)更加好用的注解@ConfigurationProperties。這個(gè)注解可以把同類的配置信息自動(dòng)封裝成實(shí)體類,如上獲取數(shù)據(jù)源的代碼可以改寫成下面這樣,由于篇幅的問題這里省略了setter、getter方法,但是實(shí)際開發(fā)中這個(gè)是必須的,否則無法成功注入。
@Configuration
@ConfigurationProperties(prefix = “jdbc.mysql”)
public class DataSouceConfiguration2 {
public String url;
public String user;
public String password;
@Bean
public DataSource dataSource() {
DataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(password);
return ds;
}
}
@EnableConfigurationProperties 注解表示對(duì)@ConfigurationProperties的內(nèi)嵌支持,
默認(rèn)會(huì)將對(duì)應(yīng)Properties Class作為Bean 注入到IOC容器中,即在相應(yīng)的Properties 類上不用加@Component注解。
組合注解
當(dāng)可能大量同時(shí)使用到幾個(gè)注解到同一個(gè)類上,就可以考慮將這幾個(gè)注解到別的注解上,被注解的注解我們就稱之為組合注解,例如@SpringBootApplication注解。
元注解:可以注解到別的注解上的注解。
組合注解:被注解的注解我們就稱之為組合注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
如上@SpringBootApplication注解上注解了@SpringBootConfiguration,@EnableAutoConfiguration以及@ComponentScan三個(gè)元注解。
總結(jié)
本文首先介紹了JavaConfig講到了注解與Spring的XML配置文件中的節(jié)點(diǎn)的配置關(guān)系,接著就是介紹了各種常用的注解。希望對(duì)讀者們有所幫助。
作者:碼農(nóng)飛哥
微信公眾號(hào):碼農(nóng)飛哥