[spring注解]Spring相關(guān)注解(三)

前言

??接上文,本篇文章主要來學(xué)習(xí)下spring-beans,spring-core,spring-webmvc對應(yīng)jar包中相關(guān)注解,其中spring-beans注解大概有:AutowiredQualifier ,RequiredLookup ,Value ;spring-core中注解大概有:OrderAliasFor ;spring-webmvc中注解有:EnableWebMvc。

一、spring-beans相關(guān)注解

1. Autowired 和 Qualifier 注解

??Autowired注解是Spring提供的用于注入bean使用的,默認(rèn)情況下按照類型進(jìn)行自動注入(byType),如果根據(jù)類型找不到或有多個(gè)類型的話,就會拋出異常。如果我們想讓Spring 在找不到對應(yīng)的bean的時(shí)候不拋出異常,可以使用該注解唯一的一個(gè)參數(shù):required,默認(rèn)是true,我們可以配置為false,這樣的話,如果找不到對應(yīng)的bean,那么該屬性就將被設(shè)置為null,而不會拋出異常。
??該注解能用于的地方特別多,類上,方法上,屬性上,構(gòu)造方法上等,不過有一點(diǎn)可能需要我們簡單注意下:

一般情況下,Autowired注解的required屬性可以用于該注解所使用的任意地方。但是當(dāng)用到構(gòu)造器上的時(shí)候,只有一個(gè)構(gòu)造器可以將required屬性設(shè)置為true,其他構(gòu)造器只能將該值設(shè)置為false。此外,當(dāng)使用該注解標(biāo)注多個(gè)構(gòu)造器時(shí),Spring會從所有滿足注入條件的狗在其中選擇入?yún)⒆疃嗟哪莻€(gè)構(gòu)造器。

我們可以來簡單看下它的實(shí)現(xiàn):

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
}

我們來簡單看一個(gè)例子:

接口UserService:

public interface UserService {
    User getUserById();
}

對應(yīng)的實(shí)現(xiàn):

@Service
public class UserServiceImpl implements UserService{
    @Override
    public User getUserById() {
        User user = new User();
        user.setId("123");
        user.setName("zhangsan");
        user.setaDouble(123.34D);
        return user;
    }
}

簡單測試:

@RestController
public class HelloController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/test1.html", method = RequestMethod.GET)
    public String test1(HttpServletRequest request) {
        User user = userService.getUserById();
        System.out.println(user.getId());
        System.out.println(user.getaDouble());
        System.out.println(user.getName());
        return "test1";
    }

簡單測試下,沒什么問題,該打印的都打印了。然后我們再給該接口添加一個(gè)實(shí)現(xiàn):

@Service
public class UserServiceImpl2 implements UserService{
    @Override
    public User getUserById() {
        User user = new User();
        user.setId("456");
        user.setName("zhang");
        user.setaDouble(123.34D);
        return user;
    }
}

當(dāng)有兩個(gè)實(shí)現(xiàn)的時(shí)候,也就是通過類型可以查找到多個(gè)的時(shí)候,Spring區(qū)分不出來是哪個(gè)bean,將會直接拋出異常。而這個(gè)時(shí)候,我們可以配合使用Spring的@Qualifier注解來解決這個(gè)問題。

@Autowired
@Qualifier("userService")
private UserService userService;

@Qualifier注解有一個(gè)參數(shù):value,該屬性表示bean在Spring中對應(yīng)的id。通過指定@Qualifier注解的value屬性,顯式的將@Autowired的byType自動注入轉(zhuǎn)換為byName的注入。

@Qualifier注解也可以用來標(biāo)注我們的實(shí)現(xiàn)類,從而對bean的范圍做一個(gè)限制。當(dāng)然我們也可以自定義注入屬性,這就用到@Qualifier的另一個(gè)功能了,也就是將Qualifier作為元注解,在此基礎(chǔ)上自定義我們的注解。

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface UserAnnotation {
}

通過自定義的@UserAnnotation注解,用來標(biāo)記我們對應(yīng)的類:

@Service
@UserAnnotation
public class UserServiceImpl implements UserService{
}

這樣,我們就可以在需要的時(shí)候使用該注解來進(jìn)行注入:

@Autowired
@UserAnnotation
private UserService userService;

另,注意下:

As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean only defines one constructor to begin with. However, if several constructors are available, at least one must be annotated to teach the container which one to use.

有關(guān)@Autowired注解 對應(yīng)官網(wǎng)文檔:https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/beans.html#beans-autowired-annotation

2. Required 注解

該注解用于Spring bean屬性的setter方法,用來強(qiáng)制性設(shè)置該屬性必須存在,如果該屬性不存在,則會拋出異常,該注解通過RequiredAnnotationBeanPostProcessor來實(shí)現(xiàn)。

public class SimpleMovieLister {

    private MovieFinder movieFinder;
    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

通過@Required注解注釋了之后,那么在進(jìn)行注入的時(shí)候,該MovieFinder對象必須要有注入的值,否則就會直接報(bào)錯(cuò);

3. Lookup 注解

??和XML配置中bean的 lookup-method方法類似,該注解是Spring提供的用于動態(tài)獲取新的實(shí)例的注解。我們來簡單分析下:

It is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean.

  1. 比如,當(dāng)我們在一個(gè)bean中依賴其他的bean時(shí),我們可以通過setter或者構(gòu)造器方法注入其他依賴的bean,這樣調(diào)用get方法的時(shí)候返回在bean中注入的實(shí)例。但是如果我們希望在每次調(diào)用get方法的時(shí)候都返回新的實(shí)例,(適用于單例bean依賴于原型bean的情況,因?yàn)閱卫齜ean只會實(shí)例化一次,而內(nèi)部依賴的bean也只會被實(shí)例化一次),這時(shí)候就可以通過該注解來實(shí)現(xiàn);
  2. 由于底層是通過cglib動態(tài)生成的,所以我們要注入的類不能是final修飾的;
  3. 該注解適用的就是單例bean依賴原型bean,而單例bean依賴單例bean,原型bean依賴原型就不會有這樣的問題了。

具體使用可以參考StackOverFlow的一篇文章:# How to use spring @Lookup annotation?

4. Value 注解

??Value注解一般用于讀取配置文件中的參數(shù),一般情況下,為了方便和統(tǒng)一,我們通常將將配置信息存于properties文件中,然后在使用的時(shí)候通過@Value注解來解析獲取。使用該注解需要先配置下PropertySourcesPlaceholderConfigurer,一般,目前主流的配置方式,XML配置:

<context:property-placeholder ignore-resource-not-found="true" ignore-unresolvable="true"
    location="classpath*:configure/*/*.properties" file-encoding="UTF-8"/>

注解配置:

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

然后使用@Value注解來獲取數(shù)據(jù):

@Value("${username}")
private String uname;

而@Value通常也有兩種使用方式:

  • @Value("#{configProperties['key']}")
  • @Value("${key}")

@Value的參數(shù)類型是SpEL表達(dá)式,有興趣的童鞋可以學(xué)習(xí)下,功能很強(qiáng)大的表達(dá)式語言,而有關(guān)@Value的用法可以參考我前文的注解<context:property-placeholder/>。

二、Spring-core相關(guān)注解

1. Order注解

??Order注解在Spring4.0之前都是用于控制AOP中AspectJ的切面的順序,Spring4.0之后該注解做了增強(qiáng),它開始支持配置類的加載排序,及對加載在list集合中的自動注入(auto-wired)組件的排序。
??該注解只有一個(gè)value的參數(shù),用于控制順序,值越小優(yōu)先級越高。

接下來看兩個(gè)簡單的例子,首先是配置類的加載順序:

@Configuration
@Order(2)
public class BeanService1 {
    @Bean
    public User getUser() {
        User user = new User();
        user.setName("BeanService1");
        return user;
    }
}

@Configuration
@Order(13)
public class BeanService2 {
    @Bean
    public User getUser() {
        User user = new User();
        user.setName("BeanService2");
        return user;
    }
}

@Configuration
@Order(1)
public class BeanService3 {
    @Bean
    public User getUser() {
        User user = new User();
        user.setName("BeanService3");
        return user;
    }
}

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("/resource/applicationContext.xml");
        User user = ac.getBean("getUser", User.class);
        System.out.println(user.getName());
        ac.close();
    }

}

我們通過該例子來實(shí)現(xiàn) 通過名字來覆蓋Bean配置,運(yùn)行之后,可以看到,最終打印的是 BeanService2,因?yàn)锧Order值大的覆蓋掉了前面的值,當(dāng)然我們也可以配置不同的對象來查看下順序,而不是覆蓋。

可以再來看一個(gè)List的例子,地址:Spring @Order Annotation,這篇文章寫的比較詳細(xì),大家可以直接看就可以了。

該注解的使用參考自:
Instantiate beans in order in Spring?
http://ifeve.com/spring4-2/

2. AliasFor 注解

Spring4.2之后引入的@AliasFor注解,用來給注解的屬性起別名,讓人使用注解時(shí),更加的容易理解,Spring4.2中大量的注解都為value添加了別名。該注解有三個(gè)參數(shù):

  • attributevalue,別名名稱,可以看到,這兩個(gè)屬性都是用AliasFor注解來修飾的;
  • annotation,注解的類型,默認(rèn)是Annotation.class;

看一段代碼實(shí)例:

@MainBean(beanName = "mainbean")
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);

        String[] beannames = context.getBeanNamesForType(Main.class);

        //當(dāng)加上@AliasFor時(shí), 輸出"mainbean"
        //當(dāng)去掉@AliasFor注解后, 輸出"main"
        System.out.println(beannames[0]);

        context.close();
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@interface MainBean {

    @AliasFor(annotation = Component.class, attribute = "value")
    String beanName() default "";
}

代碼轉(zhuǎn)自:http://ifeve.com/spring4-2/

詳細(xì)代碼可以參考文檔實(shí)現(xiàn):https://docs.spring.io/spring/docs/current/javadoc-api/

三、Spring-webmvc 相關(guān)注解

1. EnableWebMvc 注解

這個(gè)注解很簡單,就是開啟Spring-MVC配置,添加再@Configuration 修飾的配置類上,不過只能由一個(gè)@Configuration配置類可以添加該注解,而在XML中對應(yīng)的配置是mvc:annotation-driven。然后可以繼承WebMvcConfigurerAdapter來配置Web中一些設(shè)置:

@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = MyConfiguration.class)
public class MyConfiguration  extends WebMvcConfigurerAdapter {

}

當(dāng)然也可以直接選擇實(shí)現(xiàn)WebMvcConfigurer,不過需要實(shí)現(xiàn)所有的接口,而有些是我們不需要的,所以通常我們都是繼承WebMvcConfigurerAdapter,然后又選擇的實(shí)現(xiàn)我們所需要的。比如:

@Configuration
@ComponentScans({@ComponentScan(value = {"controller", "global","controller2"}),
        @ComponentScan(value = {"service"})})
@EnableWebMvc
@EnableScheduling
public class SpringConfig extends WebMvcConfigurerAdapter {

    /**
     * 指定視圖解析器
     *
     * @return
     */
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        // 視圖的路徑
        viewResolver.setPrefix("/WEB-INF/views/");
        // 視圖名稱后綴
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    /**
     * 配置默認(rèn)servletHandler,用于靜態(tài)資源訪問
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    /**
     * 配置視圖管理器
     * @param configurer
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).favorParameter(true).ignoreAcceptHeader(false);
        configurer.mediaType("json", MediaType.APPLICATION_JSON);
        configurer.mediaType("xml", MediaType.APPLICATION_XML);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,537評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,262評論 6 342
  • 人的理性是有限的。 人在做出選擇時(shí)有兩套系統(tǒng): 一是理性分析系統(tǒng),它深入分析,但消耗注意力和精力。 二是直覺系統(tǒng),...
    躲進(jìn)小樓看燈火閱讀 522評論 0 0
  • 我們的記憶應(yīng)當(dāng)是一個(gè)一個(gè)事件 我們?nèi)绾斡洃洠?1我們的記憶與故事有關(guān) 2我們的記憶與自己經(jīng)歷的故事和重大的故事有關(guān)...
    乞力馬扎駱閱讀 198評論 0 1
  • 今年從開春到入夏,多倫多降雨不斷,諾大的安大略湖水位突破歷史記錄,時(shí)不時(shí)就聽說什么地方被水淹了。整個(gè)大多倫多地區(qū)是...
    北美之北閱讀 5,811評論 1 7

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