zoukankan      html  css  js  c++  java
  • Spring源码解析之基础应用(四)

    基于注解的容器配置

    spring允许我们用注解来代替XML配置,至于是注解更好还是XML更好视情况而定,一般开发人员喜欢使用注解来进行配置,因为这样更靠近代码;而运维更喜欢XML配置,来决定服务运行的环境,比如:数据库配置。spring不但允许两种不同配置风格的存在,甚至还能混合使用。

    谈到注解,@Autowired一定是spring应用最广泛的注解之一,一般我们是将@Autowired标注在字段上,但这个注解同样可以标注在具有多个参数的方法上,前提是这些参数能在容器内找到类型匹配的bean。

    MovieRecommender一共有3处使用了@Autowired,首先是在MovieFinder字段上标注,这是大家最熟悉的做法;其次在MovieRecommender(MovieCatalog movieCatalog)构造方法上标注,如果这个方法不标注@Autowired,spring默认会调用无参构造方法;最后在setCustomerPreferenceDao(CustomerPreferenceDao customerPreferenceDao)方法上标注,spring会传入这个方法所需要的参数bean。

    package org.example.beans;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MovieRecommender {
        @Autowired
        private MovieFinder movieFinder;
        private MovieCatalog movieCatalog;
        private CustomerPreferenceDao customerPreferenceDao;
    
        public MovieRecommender() {
            System.out.println("Construct MovieRecommender()");
        }
    
        @Autowired
        public MovieRecommender(MovieCatalog movieCatalog) {
            this.movieCatalog = movieCatalog;
            System.out.println("Construct MovieRecommender(MovieCatalog movieCatalog) ");
        }
    
        public MovieFinder getMovieFinder() {
            return movieFinder;
        }
    
        public MovieCatalog getMovieCatalog() {
            return movieCatalog;
        }
    
    
        public CustomerPreferenceDao getCustomerPreferenceDao() {
            return customerPreferenceDao;
        }
    
        @Autowired
        public void setCustomerPreferenceDao(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
    }
    
    package org.example.beans;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class MovieFinder {
    }
    
    package org.example.beans;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class MovieCatalog {
    }
    
    package org.example.beans;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class CustomerPreferenceDao {
    }
    

      

    测试用例:

        @Test
        public void test14() {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig5.class);
            MovieRecommender recommender = ac.getBean(MovieRecommender.class);
            System.out.println(recommender.getMovieFinder());
            System.out.println(recommender.getMovieCatalog());
            System.out.println(recommender.getCustomerPreferenceDao());
        }
    

      

    运行结果:

    Construct MovieRecommender(MovieCatalog movieCatalog) 
    org.example.beans.MovieFinder@35083305
    org.example.beans.MovieCatalog@8e0379d
    org.example.beans.CustomerPreferenceDao@341b80b2
    

      

    @Autowired还允许我们设置参数required,默认为true,当注入的时候找不到bean则会报错,我们可以设置required为false,当spring没有找到所需的bean,则会跳过标记了@Autowired的方法或字段。

    @Autowired也可以用于标记一个集合,当这个集合所描述的类型包含多个实现。比如下面的例子,Fruit存在Apple和Banana这两个实现,我们在FruitPlate类中分别用数组、List、Set、Map来存放Fruit元素,如果用@Autowired来标注这四个字段,spring容器会把所有实现Fruit的bean数组到这个集合,Map的key为beanName:

    package org.example.beans;
    
    public class Fruit {
    }
    
    package org.example.beans;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Apple extends Fruit {
    }
    
    package org.example.beans;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Banana extends Fruit {
    }
    
    package org.example.beans;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    @Component
    public class FruitPlate {
        @Autowired
        private Fruit[] fruits;
        @Autowired
        private List<Fruit> fruitList;
        @Autowired
        private Set<Fruit> fruitSet;
        @Autowired
        private Map<String, Fruit> fruitMap;
    
        public Fruit[] getFruits() {
            return fruits;
        }
    
        public List<Fruit> getFruitList() {
            return fruitList;
        }
    
        public Set<Fruit> getFruitSet() {
            return fruitSet;
        }
    
        public Map<String, Fruit> getFruitMap() {
            return fruitMap;
        }
    }
    

      

    测试用例:

        @Test
        public void test15() {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig5.class);
            FruitPlate fruitPlate = ac.getBean(FruitPlate.class);
            System.out.println(Arrays.toString(fruitPlate.getFruits()));
            System.out.println(fruitPlate.getFruitList());
            System.out.println(fruitPlate.getFruitSet());
            System.out.println(fruitPlate.getFruitMap());
        }
    

      

    运行结果:

    [org.example.beans.Apple@429bd883, org.example.beans.Banana@4d49af10]
    [org.example.beans.Apple@429bd883, org.example.beans.Banana@4d49af10]
    [org.example.beans.Apple@429bd883, org.example.beans.Banana@4d49af10]
    {apple=org.example.beans.Apple@429bd883, banana=org.example.beans.Banana@4d49af10}
    

      

    由于按照类型注入时可能存在多个候选bean,我们可以在类或方法上标注@Primary注解,当通过类型注入bean时存在多个实现,优先使用标记注@Primary的bean:

    @Primary
    @Component
    public class Apple extends Fruit {
    }
    
    @Component
    public class FruitPlate {
    	……
    	@Autowired
        private Fruit primary;
    	public Fruit getPrimary() {
    		return primary;
    	}
    	……
    }
    

      

    当注入primary时,会优先选用Apple所对应的bean,大家可以在测试用例里面试一下,这里就不再另外试了。

    除了@Autowired,还有另外两个属性能帮助我们完成注入,分别是:JSR-250定义的注解@Resource 和JSR-330定义的注解@Inject。@Autowired和@Inject使用同一套逻辑进行注入,先根据类型进行bean的查找,如果存在多个bean,再根据字段名查找对应的bean。@Resource允许填写name和type,如果同时指定name和type,则注入的时候会找到beanName和类型都能匹配的上的bean进行注入;如果只指定了name,则根据beanName进行查找并注入,找不到则抛出异常;如果只指定了type,则根据类型进行查找,如果找不到或者找到多个,则抛出异常;如果name和type都不指定,则根据字段名查找,找不到再回退到根据类型查找。

    @Autowired虽然是一种装配技术,但不能与之前讲到的自动装配归为一类,即便这二者从表现上来看都会为我们注入所需要的bean,但它们所使用的技术不同,执行注入的时机不同,就像鸡蛋跟鸭蛋煮熟后味道差不多,但我们不能说鸡蛋就是鸭蛋。首先从使用方式上来看@Autowired和自动装配的不同,对于@Autowired我们需要在字段或方法上标记,spring才会为我们注入,这是基于注解的注入,而自动装配我们只要提供setter方法,在<bean/>标记装配类型,spring会根据装配类型来调用setter方法,这是基于XML的注入。当然,等到后续讲到spring源码时,笔者会证明@Autowired和自动装配的处理时机不同,执行逻辑不同。

  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/beiluowuzheng/p/13833426.html
Copyright © 2011-2022 走看看