返回顶部

JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(10):通过注解(annotation)装配Bean之(@Configguration、@Component、@Value、@ComponentScan、@Autowired、@Primary、@Qualifier、@Bean)

一、通过注解(annotation)装配Bean
通过之前的学习,我们已经知道如何使用XML装配Bean,但是更多的时候已经不再推荐使用XML的方式去装配Bean,更多的时候会考虑注解(annotation)的方式去装配Bean。
使用注解的方式可以减少XML的配置,注解功能更为强大,它既能实现XML的功能,也能提供自动装配的功能,采用了自动装配后,程序员所需要做的决断就减少了,更加有利于对程序的开发,
这就是"约定优于配置"的开发原则。
在Spring中,它提供了两种方式来让Spring IoC容器发现Bean。
1.组件扫描:通过定义资源的方式,让Spring IoC容器扫描对应的包,从而把Bean装配进来。
2.自动装配:通过注解定义,使得一些依赖关系可以通过注解来完成。
通过扫描和自动装配,大部分的工程师都可以使用Java配置完成,而不是XML,这样可以有效地减少配置和引入大量ML,它解决了在Spring3之前的版本需要大量的XML的配置的问题,
这些问题曾被许多开发者诟病。由于目前注解已经成为Spring开发的主流,同时也必须了解不使用XML同样会存在一些弊端,比如系统存在多个公共配置文件(比如多个properties和xml文件),
如果写在注解里,那么这些公共配置文件就会比较分散,这样 不利于统一的管理,又或者一些来至第三方的类,而不是我们系统开发的配置文件,这时利用xml配置就会比较容易管理。
目前企业所流行的方式是,注解为主,xml为辅。

1、使用@Component装配Bean
@Component:代表Spring IoC容器会把这个类扫描生成Bean实例,其中value属性表示这个Bean的id,语法格式:@Component("beanId")或者@Component(value="beanId")
@Value:代表值的注入,注入的时候Spring IoC会自动转型。
@ComponentScan:代表进行扫描,默认是扫描当前把的路径,POJO的包名和它必须保持一致才能扫描,否则是不会自动装配Bean的。这里需要特别说明一下:

@ComponentScan存在2个配置项:第一个是basePackages,它是由base和package两个单词组成的,而package还使用了复数,意味着它可以配置一个Java包的数组,Spring会根据他的配置
扫描对应的包和子包,将配置好的Bean装配进来;第二个是basePackageClasses,他是由base,package,class三个单词组成,采用复数,意味着可以配置多个类,Spring可以根据配置的类所在的包
进行扫描装配对应配置的Bean。

贴出测试代码:

---------------------->以下着重测试注解:@Component、@Value()<-----------------------------

创建一个:UserBean.java

 1 package com.xfwl.spring.annotation;
 2 
 3 import org.springframework.beans.factory.annotation.Value;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.stereotype.Component;
 6 
 7 /**
 8  * 测试注解:@Component装配Bean
 9  * @author Jason
10  * 
11  */
12 @ComponentScan        //启动扫描当前所在包的Bean,注入Spring IoC容器
13 @Component("user")    //注入user  //@Component("user")或者@Component(value="user")
14 public class UserBean {
15     @Value("xfww")
16     private String uname;
17     @Value("123456")
18     private String upwd;
19     public UserBean(){}
20     public UserBean(String uname,String upwd){
21         this.uname=uname;
22         this.upwd=upwd;
23     }
24     public String getUname() {
25         return uname;
26     }
27     public void setUname(String uname) {
28         this.uname = uname;
29     }
30     public String getUpwd() {
31         return upwd;
32     }
33     public void setUpwd(String upwd) {
34         this.upwd = upwd;
35     }
36     @Override
37     public String toString() {
38         return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
39     }        
40 }    
View Code

 创建一个:Manager.java

 1 package com.xfwl.spring.annotation;
 2 
 3 import java.util.List;
 4 import java.util.Map;
 5 import java.util.Properties;
 6 import java.util.Set;
 7 
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.stereotype.Component;
10 /**
11  * 注解测试:@Autoired 自动装配
12  * @function  
13  * @author 小风微凉
14  * @time  2018-7-10 上午11:32:01
15  */
16 @Component("manager")
17 public class Manager{
18     @Autowired
19     private long id;
20     @Autowired
21     private String mname;
22     @Autowired
23     private int mage;
24     /******getter和setter***********/
25     public long getId() {
26         return id;
27     }
28     public void setId(long id) {
29         this.id = id;
30     }
31     public String getMname() {
32         return mname;
33     }
34     public void setMname(String mname) {
35         this.mname = mname;
36     }
37     public int getMage() {
38         return mage;
39     }
40     public void setMage(int mage) {
41         this.mage = mage;
42     }
43 }
View Code

 创建一个测试类:TestAnnotation.java

package com.xfwl.spring.annotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Spring Ioc测试
 * @function  
 * @author 小风微凉
 * @time  2018-7-10 上午9:55:15
 */
public class TestAnnotation {
    //项目相对路径
    private static final String xmlRelPath="com/xfwl/spring/assem/applicationContext.xml";
    public static void main(String[] args) {
        //通过注解拿到Spring IoC容器对象
        ApplicationContext ctx=new  AnnotationConfigApplicationContext(UserBean.class);
        //获取Bean对象
        UserBean user=(UserBean) ctx.getBean("user");        
        System.out.println(user.toString());
    }
}

 测试结果:(上面注解正常运行

1 log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
2 log4j:WARN Please initialize the log4j system properly.
3 log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
4 UserBean [uname=xfww, upwd=123456]

 ---------------------->以下着重测试注解:@ComponentScan<-----------------------------

创建几个测试类如下:

ComponScan_1.java 

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Primary;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:55:26
13  */
14 @Component("serviceImp")
15 //@Primary
16 public class ServiceImpl implements IServices {
17     @Autowired(required=true)    
18     private UserBean user;
19     @Override
20     public void show() {    
21         System.out.println(this.user.toString());
22     }
23     /**********getter和setter*******************/
24     public UserBean getUser() {
25         return user;
26     }
27     public void setUser(UserBean user) {
28         this.user = user;
29     }
30 }
View Code

  ComponScan_2.java

 1 package com.xfwl.spring.annotation.scans;
 2 
 3 import org.springframework.beans.factory.annotation.Value;
 4 import org.springframework.stereotype.Component;
 5 
 6 /**
 7  * 测试:
 8  * [1].扫描注解@ComponnetScan的属性basePackages和basePackageClasses配置项的使用
 9  * @function  
10  * @author 小风微凉
11  * @time  2018-7-12 上午9:16:15
12  */
13 @Component("scan_2")
14 public class ComponScan_2 {
15     @Value("scan_2_id")
16     private String id;
17     @Value("scan_2_info")
18     private String info;
19     /*******getter和setter************/
20     public String getId() {
21         return id;
22     }
23     public void setId(String id) {
24         this.id = id;
25     }
26     public String getInfo() {
27         return info;
28     }
29     public void setInfo(String info) {
30         this.info = info;
31     }
32     /*******重写toString方法******************/
33     @Override
34     public String toString() {
35         return "ComponScan_2 [id=" + id + ", info=" + info + "]";
36     }    
37 }
View Code

 一个管理类:ScanManage.java,且这个类中,使用扫面注解:@ComponentScan(basePackageClasses={ComponScan_1.class,ComponScan_2.class,ScanManage.class}) 

 1 package com.xfwl.spring.annotation.scans;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.stereotype.Component;
 6 
 7 /**
 8  * 测试:
 9  * [1].扫描注解@ComponnetScan的属性basePackages和basePackageClasses配置项的使用。
10  * [2].自动装配注解@Autowired,配置在属性字段或者属性字段对应的setter方法上。
11  * @function  
12  * @author 小风微凉
13  * @time  2018-7-12 上午10:06:55
14  */
15 //配置注解
16 @Component("scanManage")
17 //第二种方式:配置指定的类,通过反射注入IoC
18 @ComponentScan(basePackageClasses={ComponScan_1.class,ComponScan_2.class,ScanManage.class})
19 public class ScanManage {
20     @Autowired(required=true)
21     private ComponScan_1 scan_1;
22     private ComponScan_2 scan_2;
23     /*******getter和setter************/
24     public ComponScan_1 getScan_1() {
25         return scan_1;
26     }
27     public void setScan_1(ComponScan_1 scan_1) {
28         this.scan_1 = scan_1;
29     }
30     public ComponScan_2 getScan_2() {
31         return scan_2;
32     }
33     @Autowired(required=true)
34     public void setScan_2(ComponScan_2 scan_2) {
35         this.scan_2 = scan_2;
36     }
37     /*******重写toString方法******************/
38     @Override
39     public String toString() {
40         return "ScanManage [scan_1=" + scan_1.getId() + ", scan_2=" + scan_2.getId() + "]";
41     }    
42 }

 一个测试类:TestScan.java

 1 package com.xfwl.spring.annotation;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 5 
 6 import com.xfwl.spring.annotation.scans.ComponScan_1;
 7 import com.xfwl.spring.annotation.scans.ComponScan_2;
 8 import com.xfwl.spring.annotation.scans.ScanManage;
 9 import com.xfwl.spring.annotation.scans2.ScanManage2;
10 
11 public class TestScan {
12     //项目相对路径
13         private static final String xmlRelPath="com/xfwl/spring/assem/applicationContext.xml";
14         public static void main(String[] args) {
15             //通过注解拿到Spring IoC容器对象
16             /**
17              * ScanManage:使用了@ComponnetScan的basePackageClasses的配置项
18              * ScanManage2:使用了@ComponnetScan的basePackages的配置项
19              */
20             //ApplicationContext ctx=new  AnnotationConfigApplicationContext(ScanManage.class);//不可以把@ComponentScan注解在接口中,会报错
21             ApplicationContext ctx=new  AnnotationConfigApplicationContext(ScanManage2.class);
22             //获取Bean对象
23             ComponScan_1 scan1_1=(ComponScan_1) ctx.getBean("scan_1");        
24             System.out.println(scan1_1.toString());
25             ComponScan_2 scan1_2=(ComponScan_2) ctx.getBean("scan_2");        
26             System.out.println(scan1_2.toString());
27             ScanManage scan1Manage1=(ScanManage) ctx.getBean("scanManage");        
28             System.out.println(scan1Manage1.toString());
29         }
30 }

 测试结果:以上加粗,红色的代码,均可以正常运行,说明注解正常在跑。

总结一下:  

不可以把@ComponentScan注解在接口中,会报错

 2、获取Spring IoC容器对象的2中形式:

第一种:获取xml配置文件,产生Spring IoC容器对象,有如下几种形式。
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(xmlAbsPath);
ApplicationContext ctx=new ClassPathXmlApplicationContext(xmlRelPath);
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext(xmlRelPath);
第二种:通过注解获取Spring IoC容器对象
ApplicationContext ctx=new AnnotationConfigApplicationContext(UserBean.class);
特别说明:UserBean类中必须使用注解:@ComponentScan才可以扫描包下面的POJO装配Bean注入到Spring Ioc容器中。

 3、自动装配-@Autowired

上面的注解都没有给Bean对象的属性注入对象,关于这个问题,在注解中略微有点复杂,在大部分情况下建议使用自动装配,因为这样可以减少配置的复杂度,
所以这里先介绍自动装配。
通过学习Spring IoC容器,我们知道Spring是先完成Bean的定义和生成,然后寻找需要注入的资源。也就是当Spring生成所有的Bean后,然后发现这个注解,
它就会在Bean中查找,然后找到对应的类型,将其注入进来,这样就完成了依赖注入了。所谓自动装配技术是一种由Spring自己发现对应的Bean,自动完成装配工作的方式,
它会应用到一个十分常用的注解@Autowrired,这个时候Spring IoC容器会自动根据类型去寻找定义的Bean然后将其注入。
需要注意的是,一旦配置了@Autowrired,在Spring IoC容器中就必须存在对应bean对象,否则就会Bean查找失败,在默认的情况下寻找失败它就会抛出异常,也就是说默认
情况下,Spring IoC容器会认为一定要找到对应的Bean来注入这个属性字段,有时候这并不是一个真实的需要,比如日志,有时候我们会觉得这个字段可有可无,这个时候可以通过
@Autowired的配置项required来改变它,比如@Autowired(required=false)。

以下贴出测试代码:

@Autowired 注解普通属性字段:

 1 package com.xfwl.spring.annotation;
 2 
 3 import java.util.List;
 4 import java.util.Map;
 5 import java.util.Properties;
 6 import java.util.Set;
 7 
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.stereotype.Component;
10 /**
11  * 注解测试:@Autoired 自动装配
12  * @function  
13  * @author 小风微凉
14  * @time  2018-7-10 上午11:32:01
15  */
16 @Component("manager")
17 public class Manager{
18     @Autowired
19     private long id;
20     @Autowired
21     private String mname;
22     @Autowired
23     private int mage;
24     /******getter和setter***********/
25     public long getId() {
26         return id;
27     }
28     public void setId(long id) {
29         this.id = id;
30     }
31     public String getMname() {
32         return mname;
33     }
34     public void setMname(String mname) {
35         this.mname = mname;
36     }
37     public int getMage() {
38         return mage;
39     }
40     public void setMage(int mage) {
41         this.mage = mage;
42     }
43 }

 @Autowired 注解引用类型字段:

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Primary;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:55:26
13  */
14 @Component("serviceImp")
15 //@Primary
16 public class ServiceImpl implements IServices {
17     @Autowired(required=true)    
18     private UserBean user;
19     @Override
20     public void show() {    
21         System.out.println(this.user.toString());
22     }
23     /**********getter和setter*******************/
24     public UserBean getUser() {
25         return user;
26     }
27     public void setUser(UserBean user) {
28         this.user = user;
29     }
30 }

       正如之前所谈到的在默认情况下是必须注入成功的,所以这里的required的默认值为true。当把配置修改为false时,就告诉Spring IoC容器,假如在已经定义好的Bean中查找
不到的对应的类型,允许不注入,这样也就没有异常抛出,只是这个字段可能为空,开发者自行校验,以免发生空指针异常。在大部分情况下,都不需要这样修改。
@Autowired除可以配置在属性字段上外,还可以配置在方法上,常见的Bean的setter方法也可以使用它完成注入。 

1     private UserBean user;
2     /**********getter和setter*******************/
3     @Autowired(required=true)
4     public void setUser(UserBean user) {
5         this.user = user;
6     }

        在大部分配置中,推荐使用@Autowired注解,这是Spring IoC容器自动装配完成的,使得配置大幅度减少,满足约定优于配置的原则,增强程序的健壮性。 

4、自动装配的歧义性(@Primary和@Qualifier)
        上面谈到了@Autowired注解,它可以完成一些自动装配功能,并且使用方式十分简单,但是有时候这样的当时并不能使用。这一切的根源来至于按类型的方式,按照Spring的建议,
在大部分情况下会使用接口编程,但是定义一个接口,并不一定只有一个与之对应的实现类。换句话说,一个接口可以有多个实现类。
下面介绍2中消除歧义性的注解,其消除歧义性的理念也不同:
第一种注解@Primary:
注解@Primary代表首要的,当Spring IoC通过一个接口或者抽象类注入对象的时候,由于存在多个实现类或者具体类,就会犯糊涂,不知道采用哪个类为好。
注解@Primary则是告诉Spring IoC容器,请优先该类注入。也就是说,使用了@Primary注解的类将被Spring IoC容器作为优先选择被注入,这样可以消除歧义性。
同样的,或许你会想到将@Primary注解到同一个接口的多个实现类中,这样就会存在多个首选的接口了,但是在Spring IoC容器中这样的定义是允许的,只是在注入的时候将
会抛出异常。但是无论如何@Primary只能解决首要性的问题,而不能解决选择性的问题,简而言之,它不能选择使用接口具体的实现类去注入,仅仅提供一个首要性的选择倾向。

创建2个实现同一个接口的实现子类:

实体POJO类:UserBean.java

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Value;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.stereotype.Component;
 6 
 7 /**
 8  * 测试注解:@Component装配Bean
 9  * @author Jason
10  * 
11  */
12 @Component("user")    //注入user  //@Component("user")或者@Component(value="user")
13 public class UserBean {
14     @Value("xfww")
15     private String uname;
16     @Value("123456")
17     private String upwd;
18     public UserBean(){}
19     public UserBean(String uname,String upwd){
20         this.uname=uname;
21         this.upwd=upwd;
22     }
23     public String getUname() {
24         return uname;
25     }
26     public void setUname(String uname) {
27         this.uname = uname;
28     }
29     public String getUpwd() {
30         return upwd;
31     }
32     public void setUpwd(String upwd) {
33         this.upwd = upwd;
34     }
35     @Override
36     public String toString() {
37         return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
38     }    
39     
40 }    
View Code

 接口:IServices.java 

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.context.annotation.ComponentScan;
 4 import org.springframework.stereotype.Component;
 5 
 6 /**
 7  * 服务接口:测试注解@Qualifier
 8  * @function  
 9  * @author 小风微凉
10  * @time  2018-7-12 上午11:52:29
11  */
12 @Component(value="service")
13 public interface IServices {
14     public void show();
15 }

 第一个实现子类:ServiceImpl.java 

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Primary;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:55:26
13  */
14 @Component("serviceImp")
15 @Primary
16 public class ServiceImpl implements IServices {
17     @Autowired(required=true)    
18     private UserBean user;
19     @Override
20     public void show() {    
21         System.out.println(this.user.toString());
22     }
23     /**********getter和setter*******************/
24     public UserBean getUser() {
25         return user;
26     }
27     public void setUser(UserBean user) {
28         this.user = user;
29     }
30 }

 第二个实现子类:ServiceImpl2.java(在此类中使用注解@Primary

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Primary;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:55:26
13  */
14 @Component("serviceImp")
15 @Primary
16 public class ServiceImpl implements IServices {
17     @Autowired(required=true)    
18     private UserBean user;
19     @Override
20     public void show() {    
21         System.out.println(this.user.toString());
22     }
23     /**********getter和setter*******************/
24     public UserBean getUser() {
25         return user;
26     }
27     public void setUser(UserBean user) {
28         this.user = user;
29     }
30 }

 在创建一个逻辑管理类:UserManage.java(在此类中添加注解扫描器)

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.context.annotation.ComponentScan;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:58:56
13  */
14 @Component("manager")
15 @ComponentScan(basePackages={"com.xfwl.spring.annotation.qualifier"})//启动扫描当前所在包的Bean,注入Spring IoC容器
16 public class UserManage {
17     @Autowired(required=true)
18     //@Qualifier("serviceImp2")
19     private IServices service;
20     
21     public void show(){
22         this.service.show();
23     }
24     /**********getter和setter*******************/
25     public IServices getService() {
26         return service;
27     }
28     public void setService(IServices service) {
29         this.service = service;
30     }
31 }

 再来一个测试类:TestScan.java

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 5 
 6 import com.xfwl.spring.annotation.scans.ComponScan_1;
 7 import com.xfwl.spring.annotation.scans.ComponScan_2;
 8 import com.xfwl.spring.annotation.scans.ScanManage;
 9 import com.xfwl.spring.annotation.scans2.ScanManage2;
10 
11 public class TestScan {
12     //项目相对路径
13         private static final String xmlRelPath="com/xfwl/spring/assem/applicationContext.xml";
14         public static void main(String[] args) {            
15             ApplicationContext ctx=new  AnnotationConfigApplicationContext(UserManage.class);
16             //获取Bean对象
17             UserManage manager=(UserManage) ctx.getBean("manager");        
18             manager.show();
19         }
20 }

 测试结果:注解正常运行

第二种注解@Qualifier:
正如上面谈及到的歧义性,一个重要的原因是Spring在寻找依赖注入的时候采用按类型注入引起的。处理按照类型查找Bean,Spring IoC容器最底层的接口BeanFactory,
也定义了按照名称查找的方法,如果采用名称查找的方法,而不是采用类型查找,那么不就可以消除歧义性了吗?答案是肯定的!而注解@Qualifier就是这样一个注解。

 测试代码如下:(由于注解@Primary和注解@Qualifier的测试代码及其相似,所以以下会修改上面的代码来完成测试

修改ServiceImpl.java,修改部分如下:

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Primary;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:55:26
13  */
14 @Component("serviceImp")
15 //@Primary
16 public class ServiceImpl implements IServices {
17     @Autowired(required=true)    
18     private UserBean user;
19     @Override
20     public void show() {    
21         System.out.println(this.user.toString());
22     }
23     /**********getter和setter*******************/
24     public UserBean getUser() {
25         return user;
26     }
27     public void setUser(UserBean user) {
28         this.user = user;
29     }
30 }
View Code

 在UserManage.java中指定:@Qualifier("serviceImp2") 

 1 package com.xfwl.spring.annotation.qualifier;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.context.annotation.ComponentScan;
 6 import org.springframework.stereotype.Component;
 7 
 8 /**
 9  * 测试注解@Qualifier
10  * @function  
11  * @author 小风微凉
12  * @time  2018-7-12 上午11:58:56
13  */
14 @Component("manager")
15 @ComponentScan(basePackages={"com.xfwl.spring.annotation.qualifier"})//启动扫描当前所在包的Bean,注入Spring IoC容器
16 public class UserManage {
17     @Autowired(required=true)
18     @Qualifier("serviceImp2")
19     private IServices service;
20     
21     public void show(){
22         this.service.show();
23     }
24     /**********getter和setter*******************/
25     public IServices getService() {
26         return service;
27     }
28     public void setService(IServices service) {
29         this.service = service;
30     }
31 }

 测试结果:注解正常运行

5、装载带有参数的构造方法类:

贴出测试代码: 

 1 package com.xfwl.spring.annotation.qualifier;
 2 import org.springframework.beans.factory.annotation.Autowired;
 3 import org.springframework.stereotype.Component;
 4 @Component("serviceImp")
 5 public class ServiceImpl implements IServices {
 6     private UserBean user;
 7     public ServiceImpl(@Autowired UserBean user){//测试通过
 8         this.user=user;
 9     }
10     @Override
11     public void show() {    
12         System.out.println(this.user.toString());
13     }
14 }

 或者 

 1 package com.xfwl.spring.annotation.qualifier;
 2 import org.springframework.beans.factory.annotation.Qualifier;
 3 import org.springframework.stereotype.Component;
 4 @Component("serviceImp3")
 5 public class ServiceImpl3 implements IServices {
 6     private UserBean user;
 7     public ServiceImpl3(@Qualifier UserBean user){//测试不通过,不支持注解@Qualifier注入构造器的参数
 8         this.user=user;
 9     }
10     @Override
11     public void show() {    
12         System.out.println(this.user.toString());
13     }
14 }

 从上面的代码,可以看出:这种注解并没有放在属性字段或者属性的setter方法上,而是直接放在构造器上的。

6、使用@Bean装配Bean

      以上描述的用法都是通过@Componnet注解装配Bean,但是@Componnet只能注解在类上,不能注解在方法上。对于Java而言,大部分的开发都需要引入第三方的包(Jar文件),而且往往
并没有这些包的源码,这时候无法为这些包的类加入@Componnet注解,让他们变为开发环境的Bean.你可以使用新类扩展(extends)其包内的类,然后在新类上使用@Componnet,但是这样又显得
不伦不类。
     这个时候Spring给与一个注解@Bean,它可以注解到方法上,并且讲方法返回的对象作为Spring的Bean存放在IoC容器中。比如我们需要用到的DBCP数据源。

现在来测试一下:

 1 package com.xfwl.spring.annotation.bean;
 2 
 3 import java.util.Properties;
 4 
 5 import javax.sql.DataSource;
 6 
 7 import org.apache.commons.dbcp2.BasicDataSourceFactory;
 8 import org.springframework.context.annotation.Bean;
 9 import org.springframework.context.annotation.ComponentScan;
10 
11 @ComponentScan(basePackages={"com.xfwl.spring.annotation.bean"})
12 public class ManagerScan {
13     @Bean(name="ds")
14     public DataSource getDataSource(){
15         Properties props=new Properties();
16         props.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
17         props.setProperty("url", "jdbc:oracle:thin:@***.**.17.33:1521:**");
18         props.setProperty("username", "***");
19         props.setProperty("password", "***");
20         DataSource dataSource=null;
21         try {
22             dataSource=BasicDataSourceFactory.createDataSource(props);
23         } catch (Exception e) {
24             e.printStackTrace();
25         }
26         return dataSource;        
27     }
28 }

 以及

 1 package com.xfwl.spring.annotation.bean;
 2 import java.util.Properties;
 3 
 4 import javax.sql.DataSource;
 5 import org.apache.commons.dbcp2.BasicDataSourceFactory;
 6 import org.springframework.context.ApplicationContext;
 7 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 8 import org.springframework.context.annotation.Bean;
 9 import org.springframework.context.annotation.ComponentScan;
10 import org.springframework.stereotype.Component;
11 @Component("test")
12 public class TestBean {
13     public static void main(String[] args) {        
14         //通过注解获取IoC容器对象
15         ApplicationContext ctx=new  AnnotationConfigApplicationContext(ManagerScan.class);
16         System.out.println(ctx.getBean("ds").toString());
17     } 
18 }

 测试结果显示:可以从Spring IoC容器中拿到ds这个Bean对象。

7、注解自定义Bean的初始化和销毁方法:

  注解@Bean不能使用在类的标注上,它主要使用在方法上,@Bean的配置项包含4个配置项:

  • name:是一个字符串数组,允许配置多个BeanName。
  • autowire:标志是否是一个引用的Bean对象,默认值是AutoWire.No。
  • initKMethod:自定义初始化方法。
  • destoryMethod:自定义销毁方法。

基于上面的描述,自定义初始化的方法是initMethod,销毁的方法则是destoryMethod。

贴出测试代码:

创建一个基本POJO类:UserBean.java (内置自定义的初始化和销毁方法

 1 package com.xfwl.spring.annotation.bean;
 2 
 3 import org.springframework.beans.factory.annotation.Value;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.stereotype.Component;
 6 
 7 /**
 8  * 测试注解:@Component装配Bean
 9  * @author Jason
10  * 
11  */
12 @Component("user")    //注入user  //@Component("user")或者@Component(value="user")
13 public class UserBean {
14     @Value("xfww")
15     private String uname;
16     @Value("123456")
17     private String upwd;
18     public UserBean(){}
19     public UserBean(String uname,String upwd){
20         this.uname=uname;
21         this.upwd=upwd;
22     }
23     public String getUname() {
24         return uname;
25     }
26     public void setUname(String uname) {
27         this.uname = uname;
28     }
29     public String getUpwd() {
30         return upwd;
31     }
32     public void setUpwd(String upwd) {
33         this.upwd = upwd;
34     }
35     @Override
36     public String toString() {
37         return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
38     }    
39     /**Bean生命周期测试**/
40     public void init(){
41         System.out.println("【"+this.getClass().getSimpleName()+"】执行自定义初始化方法!");
42     }
43     public void mydestory(){
44         System.out.println("【"+this.getClass().getSimpleName()+"】执行自定义销毁法!");
45     }
46 }    

 创建一个测试@Bean的类:(特别说明一下:注解@Configuration表示是告诉spring这个类是一个配置类,相当于我们的xml配置文件

 1 package com.xfwl.spring.annotation.bean;
 2 
 3 import org.springframework.beans.factory.BeanNameAware;
 4 import org.springframework.beans.factory.DisposableBean;
 5 import org.springframework.beans.factory.InitializingBean;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.ComponentScan;
 9 import org.springframework.context.annotation.Configuration;
10 @Configuration
11 @ComponentScan(basePackages={"com.xfwl.spring.annotation.bean"})
12 public class ManagerScan{    
13     @Bean(name={"tom","jack"},initMethod="init",destroyMethod="mydestory")
14     public UserBean getUser(@Autowired UserBean user){
15         return user;
16     }    
17 }

 创建一个测试类: 

 1 package com.xfwl.spring.annotation.bean;
 2 import java.util.Properties;
 3 
 4 import javax.sql.DataSource;
 5 
 6 import org.apache.commons.dbcp2.BasicDataSourceFactory;
 7 import org.springframework.context.ApplicationContext;
 8 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 9 import org.springframework.context.annotation.Bean;
10 import org.springframework.context.annotation.ComponentScan;
11 import org.springframework.stereotype.Component;
12 @Component("test")
13 public class TestBean {
14     public static void main(String[] args) {        
15         //通过注解获取IoC容器对象
16         AnnotationConfigApplicationContext ctx=new  AnnotationConfigApplicationContext(ManagerScan.class);
17         UserBean user=(UserBean) ctx.getBean("tom");
18         System.out.println(user.toString());
19         ctx.close();        
20     } 
21 }

 测试结果:

1 log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
2 log4j:WARN Please initialize the log4j system properly.
3 log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
4 【UserBean】执行自定义初始化方法!
5 UserBean [uname=xfww, upwd=123456]
6 【UserBean】执行自定义销毁法!

 

posted @ 2018-07-12 13:51  小风微灵-彦  阅读(730)  评论(0编辑  收藏  举报
加载中……