Spring注解整理

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)。

image.png

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})
image.png

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})
image.png

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ì)象。

image.png

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;
    }
}

image.png

最后的執(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)行使用。


image.png

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);
        }
    }
}
image.png

可以看到“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);
    }
}
image.png

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í)也拿不到配置文件的信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容