1.@Configuration
使用這個(gè)注解來(lái)告訴Spring這是一個(gè)配置類(lèi),來(lái)替代原來(lái)的
<bean id="xxx" class="xxxx">
<property name ="xx" value = "xx"></property>
<property name ="xx1" value = "xx1"></property>
</bean>
2.@Bean
使用這個(gè)注解將一個(gè)對(duì)象實(shí)例注冊(cè)進(jìn)IOC容器中作為一個(gè)bean,默認(rèn)的bean id為訪問(wèn)名,也可以顯示指定id以及init、destroy方法,如@Bean(name = "sunwukong",initMethod = "init",destroyMethod = "destroy")
除了可以在注解中指定init、destroy方法外,還可以通過(guò)實(shí)現(xiàn)InitializingBean與DisposableBean來(lái)實(shí)現(xiàn)bean的初始化與銷(xiāo)毀邏輯。
3.@ComponentScan
在原來(lái)的Spring xml配置文件中需要配置
<context:component-scan base-package="com.xxx"></context>
來(lái)表示將這個(gè)包下的帶有@Controller、@Service、@Repository、@Component的類(lèi)都注冊(cè)到IOC容器里面。
現(xiàn)在可以在@Configuration標(biāo)注的配置類(lèi)(相當(dāng)于原xml配置文件)上標(biāo)注@ComponentScan(value = "com.xxx")
里面可以添加excludeFilters = {} 、includeFilters = {}等用于過(guò)濾,@ComponentScans(value= {@ComponentScan})可以寫(xiě)多個(gè)。
4.@Filter
在上面說(shuō)到的excludeFilters、includeFilters數(shù)組中可以添加@Filter注解的過(guò)濾器。如
excludeFilters = {
@Filter(type=FilterType.Annotation,classes={Controller.class,Service.class},useDefaultFilters=false)
}
includeFilters = {
@Filter(type=FilterType.Annotation,classes={Controller.class,Service.class})
}
5.@Scope
在@Bean將實(shí)例注入IOC時(shí),可以通過(guò)@Scope設(shè)置4種模式。
singleton(單例)、prototype(原型)、request(同一個(gè)請(qǐng)求一個(gè)實(shí)例)、session(同一個(gè)會(huì)話一個(gè)實(shí)例)。默認(rèn)是單例,對(duì)象為啟動(dòng)時(shí)創(chuàng)建,為餓漢式。若設(shè)置為prototype則對(duì)象為每次獲取時(shí)創(chuàng)建,為懶漢式。
6.@Lazy
單實(shí)例bean可以標(biāo)注此注解,用于將默認(rèn)的餓漢式變?yōu)閼屑虞d即第一次獲取對(duì)象時(shí)創(chuàng)建。
7.@Conditional
這個(gè)注解根據(jù)條件來(lái)注冊(cè)bean,可以放在方法上或者類(lèi)上(滿足條件類(lèi)中的所有都會(huì)生效),下面是例子:
// 配置類(lèi)
@Configuration
public class MainConfig {
@Bean("sunwukong")
@Conditional({LinuxCondition.class})
public Person persion01(){
return Person.builder().name("孫悟空").age(18).build();
}
@Bean("zhubajie")
@Conditional({WindowsCondition.class})
public Person persion02(){
return Person.builder().name("豬八戒").age(17).build();
}
}
// 自定義condition條件
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = ctx.getEnvironment();
String osName = env.getProperty("os.name");
return osName.contains("Windows");
}
}
// 自定義condition條件
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = ctx.getEnvironment();
String osName = env.getProperty("os.name");
return osName.contains("Linux");
}
}
8. @Import
自己寫(xiě)的組件使用@Component``@Controller``@Service``@Dao來(lái)標(biāo)注
第三方的組件使用@Bean來(lái)注冊(cè)
如果嫌寫(xiě)@Bean麻煩,可以使用@Import直接導(dǎo)入組件,默認(rèn)id為全類(lèi)名。@Import({A.class,B.class})參數(shù)可以是數(shù)組同時(shí)導(dǎo)入多個(gè)類(lèi)。

9.@Import通過(guò)ImportSelector注冊(cè)bean
可以自定義導(dǎo)入什么樣的組件。
// 自定義importSelect
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// annotationMetadata參數(shù)可以獲取注解等值
// 不要返回null
return new String[]{"com.zmz.al.bean.Red","com.zmz.al.bean.Yellow"};
}
}
// 配置類(lèi)中注解導(dǎo)入
@Import({Color.class, MyImportSelector.class})

10.@Import通過(guò)BeanDefinitions手動(dòng)注冊(cè)
自定義一個(gè)MyBeanDefinationRegistrar
public class MyBeanDefinationRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 判斷是否含有黃色以及紅色,有的話添加綠色
boolean hasYellow = registry.containsBeanDefinition("com.zmz.al.bean.Yellow");
boolean hasRed = registry.containsBeanDefinition("com.zmz.al.bean.Red");
if (hasYellow && hasRed) {
// 創(chuàng)建一個(gè)beanDefination
RootBeanDefinition green = new RootBeanDefinition(Green.class);
// 可以設(shè)置bean的name
registry.registerBeanDefinition("green",green);
}
}
}
配置類(lèi)@import中加入MyBeanDefinationRegistrar.class
@Import({Color.class, MyImportSelector.class, MyBeanDefinationRegistrar.class})

11.通過(guò)BeanFatory注冊(cè)
// 新建一個(gè)類(lèi)實(shí)現(xiàn)一個(gè)FacotryBean的接口
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
@Override
public boolean isSingleton() {
// true為單例,false為原型
return true;
}
}
// 將這個(gè)新的類(lèi)注冊(cè)到IOC容器
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
// 測(cè)試類(lèi)
@Test
public void registryTest(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
可以看到,使用ioc可以根據(jù)name獲取bean,如果有&符號(hào)表示獲取的是工廠本身,如果不加&符號(hào)則獲取的是具體的對(duì)象。

12. @PostConstruct
bean的生命周期的控制注解,在bean創(chuàng)建之后,賦值之后,進(jìn)行調(diào)用。
13. @PreDestroy
bean的生命周期的控制注解,在bean的銷(xiāo)毀之前進(jìn)行調(diào)用。
@Component
public class Dog {
private String name;
private Integer age;
@PostConstruct
public void postConstruct(){
System.out.println("dog postConstruct ...");
}
@PreDestroy
public void preDestroy(){
System.out.println("dog preDestroy...");
}
}
14.使用BeanPostProcessor控制bean的生命周期
// 新建一個(gè)dog類(lèi)
public class Dog {
private String name;
private Integer age;
@PostConstruct
public void postConstruct(){
System.out.println("dog postConstruct ...");
}
@PreDestroy
public void preDestroy(){
System.out.println("dog preDestroy...");
}
public void init(){
System.out.println("dog init...");
}
public void destroy(){
System.out.println("dog destroy...");
}
}
// 配置類(lèi)中@Bean注冊(cè)dog bean并標(biāo)明init、destroy方法
@Bean(name = "dog",initMethod = "init",destroyMethod = "destroy")
public Dog dog(){
return new Dog();
}
// 構(gòu)建beanProcessor類(lèi)
@Component
public class MyBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前處理beanName:"+beanName+",bean:"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后處理beanName:"+beanName+",bean:"+bean);
return bean;
}
}

最后的執(zhí)行順序?yàn)?code>postProcessBeforeInitialization,
postConstruct,init,postProcessAfterInitialization,preDestroy,destroy
15.@Value
給bean賦值,1)可以是基本數(shù)值;2)可以使用Spring表達(dá)式SPEL,#{};3)使用${}讀取配置文件中的值或者運(yùn)行環(huán)境變量中的值??梢苑旁谌肿兞炕蛘叻椒▍?shù)上。
16.PropertySource(value="classpath:person.properties")
使用該注解加載外部配置文件保存到運(yùn)行的環(huán)境變量中,然后再使用@Value讀取配置文件。
<context:property-placeholder location="classpath:person.properties" />
17. @Autowired、@Qualifier
默認(rèn)按照類(lèi)型去尋找IOC容器中的組件。如何同一類(lèi)型的找到了多個(gè),那么默認(rèn)就根據(jù)屬性名去尋找,如private ADAO aDao;就根據(jù)aDao這個(gè)名稱(chēng)去尋找。還可以顯示的指定使用@Qualifier("aDao")注解來(lái)指定具體的名字。如何IOC中沒(méi)有這個(gè)組件的情況下,可以在@Autowired(required=false)標(biāo)明是非必須的。
@Autowired可以標(biāo)注在方法上,表示其中的參數(shù)會(huì)通過(guò)類(lèi)型去IOC中找到對(duì)應(yīng)的bean。如set方法,有參構(gòu)造器方法。
還可以標(biāo)注在參數(shù)上public void aaa(@Autowired A a){},標(biāo)在有參構(gòu)造器上如果參數(shù)為1個(gè)時(shí),可以省略。
@Bean時(shí)方法中的參數(shù)也可以省略@autowired注解,自動(dòng)會(huì)去IOC容器中尋找bean。
18.@Primary
注冊(cè)bean時(shí),同類(lèi)型多個(gè)bean中可以在其中一個(gè)標(biāo)明此注解,來(lái)作為一個(gè)首選項(xiàng),這樣依賴(lài)注入@Autowired的時(shí)候就可以?xún)?yōu)先拿到首選的bean了。注意@Qualifier優(yōu)先級(jí)大于@Primary。
19.@Resource
是Java規(guī)范的依賴(lài)注入的注解,而@Autowired是Spring的注解。
@Resource默認(rèn)按照組件名稱(chēng)進(jìn)行裝配。或者顯示的@Resource(name="aDao")來(lái)指定具體的bean。不能結(jié)合@Qualifier、@Primary注解,且不能使用required=false屬性。
20.@Inject
是Java規(guī)范的依賴(lài)注入的注解,但是使用時(shí)需要引入一個(gè)javax.inject的包。
21.Spring底層Aware的使用
自定義組件想要使用Spring底層的組件時(shí),可以實(shí)現(xiàn)xxxAware接口再進(jìn)行使用。

22.@Profile
可以添加在方法上或者類(lèi)上。
給組件添加標(biāo)識(shí),滿足條件的bean才能被注冊(cè)到IOC容器之中。默認(rèn)@Profile("default")的會(huì)被注冊(cè)。
1)使用配置文件中的spring.prifiles.active=xxx來(lái)指定現(xiàn)在使用的環(huán)境標(biāo)識(shí),
2)通過(guò)JVM參數(shù)-Dspring.prifiles.active=xxx來(lái)指定
3)使用編碼來(lái)指定
// 先準(zhǔn)備兩個(gè)環(huán)境的Bean
@Configuration
public class ProfileConfig {
@Profile("eat")
@Bean
public Person baigujing(){
return new Person("白骨精",17);
}
@Profile("mary")
@Bean
public Person nverguoguowang(){
return new Person("女兒國(guó)國(guó)王",18);
}
@Profile("mary")
@Bean
public Person kongquegongzhu(){
return new Person("孔雀公主",16);
}
}
// 測(cè)試類(lèi)中
public class ProfileTest {
@Test
public void profileTest(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext();
ioc.getEnvironment().setActiveProfiles("mary");
ioc.register(ProfileConfig.class);
ioc.refresh();
String[] names = ioc.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}

可以看到“eat組”的白骨精沒(méi)有注冊(cè)進(jìn)來(lái),“mary組”的孔雀公主、女兒國(guó)國(guó)王注冊(cè)進(jìn)來(lái)了。
23. aop相關(guān)注解
1.切面類(lèi)與被切的業(yè)務(wù)邏輯類(lèi)都應(yīng)該使用IOC容器管理
2.給切面類(lèi)一個(gè)注解@Aspect標(biāo)記為切面類(lèi)
3.切面類(lèi)中使用注解@Pointcut("execution(public int com.zmz.al.util.MathUtil.*(..))")編寫(xiě)切入點(diǎn)表達(dá)式來(lái)賦值切入點(diǎn)的位置
4.@Before("pointCut()")、@After("com.zmz.al.log.LogAspect.pointCut()")、@AfterReturning(value="pointCut()",returning = "ret")、@AfterThrowing(value="pointCut()",throwing = "e")
來(lái)編寫(xiě)切入點(diǎn)的前、后、返回后、異常后的生命周期自定義函數(shù)。
5.自定義的生命周期函數(shù)可以使用JoinPoint jp來(lái)獲取切點(diǎn)相關(guān)的參數(shù),如函數(shù)名稱(chēng)、函數(shù)參數(shù)列表等,這個(gè)參數(shù)一定要寫(xiě)在參數(shù)列表的第一位,還可以在注解中傳入value、returning、throwing等屬性值。
6.@EnableAspectJAutoProxy // 開(kāi)啟切面自動(dòng)代理,一般在配置類(lèi)中開(kāi)啟切面自動(dòng)代理功能
@Aspect
public class LogAspect {
// 切入點(diǎn)表達(dá)式
@Pointcut("execution(public int com.zmz.al.util.MathUtil.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void logStart(JoinPoint jp){
Object[] args = jp.getArgs();
System.out.println(jp.getSignature().getName()+"@Before運(yùn)行,參數(shù)列表是:"+ Arrays.asList(args));
}
@After("com.zmz.al.log.LogAspect.pointCut()")
public void logEnd(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"@After運(yùn)行");
}
@AfterReturning(value="pointCut()",returning = "ret")
public void logReturn(JoinPoint jp,Object ret){
System.out.println(jp.getSignature().getName()+"@AfterReturning運(yùn)行正常返回,結(jié)果是:"+ret);
}
@AfterThrowing(value="pointCut()",throwing = "e")
public void logException(JoinPoint jp,Exception e){
System.out.println(jp.getSignature().getName()+"@AfterThrowing運(yùn)行異常,異常為:"+e);
}
}

24.聲明式事務(wù)注解
1.將DataSource的事務(wù)管理器注冊(cè)到IOC容器中,整合mybatis時(shí)會(huì)自動(dòng)注冊(cè)。
2.@Transactional在方法上添加、@EnableTransactionManagement在配置類(lèi)上添加開(kāi)啟事務(wù)功能。
3.當(dāng)方法中報(bào)異常時(shí),會(huì)調(diào)用DataSource的事務(wù)管理器自動(dòng)回滾數(shù)據(jù)庫(kù)相關(guān)操作。
FAQ
1.在測(cè)試@Value注解的時(shí)候,報(bào)了Could not resolve placeholder '' in value "${}"這樣的錯(cuò)
進(jìn)一步檢查發(fā)現(xiàn)配置文件沒(méi)有打包進(jìn)入到target目錄,查找之后是因?yàn)樽约涸趐om.xml文件中配置了這個(gè)導(dǎo)致的。
<packaging>pom</packaging>
而這這個(gè)標(biāo)簽是用來(lái)指示idea將該模塊打包成pom,所以,項(xiàng)目在啟動(dòng)編譯時(shí)沒(méi)有把配置文件同步到target目錄下,項(xiàng)目運(yùn)行時(shí)也拿不到配置文件的信息。