JavaConfig與常見Annotation(必知必會系列)

文章目錄

    JavaConfig
    @ComponentScan
    @Import
    @Conditional
    @ConfigurationProperties與@EnableConfigurationProperties
    組合注解
    總結

上一篇我們介紹了 Spring中Bean的生命周期,這一篇我們接著學習在Spring Boot中的一些常用注解。

JavaConfig

說注解之前,我們先了解下JavaConfig。在注解方式實例化Bean之前,我們都是通過XML來配置Bean以及其依賴關系的,造成了項目中有大量的XML文件,使項目變得復雜,不便于維護。所以JavaConfig 就應運而生了,JavaConfig是Spring的一個子項目。它基于Java代碼和Annotation注解來描述Bean之間的依賴綁定關系。
例如: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 注解標注在類上,相當于把該類作為Spring的XML配置文件中的,其作用為:配置Spring容器,需要注意的是:

@Configuration不可以是final類型;
@Configuration 不可以是匿名類
嵌套的Configuration必須是靜態(tài)類。
@Bean 注解標注方法上(返回某個實例的方法),等價于Spring的XML配置文件中的<bean>,作用是注冊bean對象,對象實例的名字默認是方法名。我們也可以通過name 屬性來指定實例名。
@Bean 注解默認作用域為單例singleton 作用域,可通過@Scope(”prototype“)設置為原型作用域
既然@Bean的作用是注冊bean對象,那么完全可以使用@Component、@Controller、@Service、@Ripository等注解注冊bean,當然需要配置@ComponentScan注解進行自動掃描。

@ComponentScan

@ComponentScan注解對應Spring的XML配置文件中的context:component-scan/ 表示啟動組件掃描,Spring會自動掃描所有通過注解配置的bean,然后將其注冊到IOC容器中,我們可以通過basePackages屬性來指定@ComponentScan自動掃描的范圍,如果不指定,則默認從聲明@ComponentScan所在類的package進行掃描,正是因為如此,SpringBoot的啟動類都是默認在/src/main/java下。
@Import

@Import 注解用于導入配置類,應用場景就是一個配置類中的一個Bean依賴于另一個配置類中的一個Bean。例如:下面有一個TeacherConfiguration配置類。這個類里定義了一個TeacherService的實例。

@Configuration
public class TeacherConfiguration {
@Bean
public TeacherService teacherService(){
return new TeacherServiceImpl();
}
}

還有一個StudentConfiguration配置類,這個配置類中定義的StudentService的實例需要依賴TeacherService對象。所以我們在StudentConfiguration中將TeacherConfiguration引入,如下所示:

@Configuration
//可以同時導入多個配置文件,比如:@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 注解支持導入普通java類,并將其聲明成一個Bean,主要用于將多個分散的JavaConfig配置類融合成一個更大的config類。

@Import 注解在4.2之前只支持導入配置類。
在4.2之后@Import注解支持導入普通的java類,并將其聲明成一個Bean。
@Import三種使用方式:

直接導入普通的Java類。
配合自定義的ImportSelector使用。
配合ImportBeanDefinitionRegistrar使用。

@Conditional

@Conditional注解表示滿足某種條件之后才開始初始化一個Bean或者啟動某些配置,它一般用在由@Component、@Service、@Configuration等注解標識的類上面,或者由@Bean標記的方法上。如果一個@Configuration類標記了 @Conditional,則該類中所有標識了@Bean的方法和@Import注解導入的相關類將遵從這些條件。
如果我們需要自定義自己的條件類,所要做的就是實現(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;
}
}

當你用Java來聲明Bean的時候,可以使用這個自定義條件類:

@Conditional(JdbcTemplateCondition.class)
@Service
public class JdbcDemoService {

}

這個栗子中只有當JdbcTemplateCondition類的條件成立時才會創(chuàng)建JdbcDemoService這個Bean,也就是說JdbcDemoService這個Bean的創(chuàng)建條件是classpath里面包括JdbcTemplate,否則這個bean的聲明就會被忽略掉。
在SpringBoot中還有一些有意思的條件注解。

@ConfigurationProperties與@EnableConfigurationProperties

當某些屬性的值需要配置的時候,我們一般會在applcation.properties文件中新建配置項,然后通過@Value注解來獲取配置項,比如下面配置數(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了,代碼也不美觀。沒關系,我們還有個更加好用的注解@ConfigurationProperties。這個注解可以把同類的配置信息自動封裝成實體類,如上獲取數(shù)據(jù)源的代碼可以改寫成下面這樣,由于篇幅的問題這里省略了setter、getter方法,但是實際開發(fā)中這個是必須的,否則無法成功注入。

@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 注解表示對@ConfigurationProperties的內(nèi)嵌支持,
默認會將對應Properties Class作為Bean 注入到IOC容器中,即在相應的Properties 類上不用加@Component注解。
組合注解

當可能大量同時使用到幾個注解到同一個類上,就可以考慮將這幾個注解到別的注解上,被注解的注解我們就稱之為組合注解,例如@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三個元注解。
總結

本文首先介紹了JavaConfig講到了注解與Spring的XML配置文件中的節(jié)點的配置關系,接著就是介紹了各種常用的注解。希望對讀者們有所幫助。





作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥