一、通过注解(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
package com.xfwl.spring.annotation; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 测试注解:@Component装配Bean
* @author Jason
*
*/
@ComponentScan //启动扫描当前所在包的Bean,注入Spring IoC容器
@Component("user") //注入user //@Component("user")或者@Component(value="user")
public class UserBean {
@Value("xfww")
private String uname;
@Value("123456")
private String upwd;
public UserBean(){}
public UserBean(String uname,String upwd){
this.uname=uname;
this.upwd=upwd;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpwd() {
return upwd;
}
public void setUpwd(String upwd) {
this.upwd = upwd;
}
@Override
public String toString() {
return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
}
}
创建一个:Manager.java
package com.xfwl.spring.annotation; import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 注解测试:@Autoired 自动装配
* @function
* @author 小风微凉
* @time 2018-7-10 上午11:32:01
*/
@Component("manager")
public class Manager{
@Autowired
private long id;
@Autowired
private String mname;
@Autowired
private int mage;
/******getter和setter***********/
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public int getMage() {
return mage;
}
public void setMage(int mage) {
this.mage = mage;
}
}
创建一个测试类: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());
}
}
测试结果:(上面注解正常运行)
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
UserBean [uname=xfww, upwd=123456]
---------------------->以下着重测试注解:@ComponentScan<-----------------------------
创建几个测试类如下:
ComponScan_1.java
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:55:26
*/
@Component("serviceImp")
//@Primary
public class ServiceImpl implements IServices {
@Autowired(required=true)
private UserBean user;
@Override
public void show() {
System.out.println(this.user.toString());
}
/**********getter和setter*******************/
public UserBean getUser() {
return user;
}
public void setUser(UserBean user) {
this.user = user;
}
}
ComponScan_2.java
package com.xfwl.spring.annotation.scans; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; /**
* 测试:
* [1].扫描注解@ComponnetScan的属性basePackages和basePackageClasses配置项的使用
* @function
* @author 小风微凉
* @time 2018-7-12 上午9:16:15
*/
@Component("scan_2")
public class ComponScan_2 {
@Value("scan_2_id")
private String id;
@Value("scan_2_info")
private String info;
/*******getter和setter************/
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
/*******重写toString方法******************/
@Override
public String toString() {
return "ComponScan_2 [id=" + id + ", info=" + info + "]";
}
}
一个管理类:ScanManage.java,且这个类中,使用扫面注解:@ComponentScan(basePackageClasses={ComponScan_1.class,ComponScan_2.class,ScanManage.class})
package com.xfwl.spring.annotation.scans; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 测试:
* [1].扫描注解@ComponnetScan的属性basePackages和basePackageClasses配置项的使用。
* [2].自动装配注解@Autowired,配置在属性字段或者属性字段对应的setter方法上。
* @function
* @author 小风微凉
* @time 2018-7-12 上午10:06:55
*/
//配置注解
@Component("scanManage")
//第二种方式:配置指定的类,通过反射注入IoC
@ComponentScan(basePackageClasses={ComponScan_1.class,ComponScan_2.class,ScanManage.class})
public class ScanManage {
@Autowired(required=true)
private ComponScan_1 scan_1;
private ComponScan_2 scan_2;
/*******getter和setter************/
public ComponScan_1 getScan_1() {
return scan_1;
}
public void setScan_1(ComponScan_1 scan_1) {
this.scan_1 = scan_1;
}
public ComponScan_2 getScan_2() {
return scan_2;
}
@Autowired(required=true)
public void setScan_2(ComponScan_2 scan_2) {
this.scan_2 = scan_2;
}
/*******重写toString方法******************/
@Override
public String toString() {
return "ScanManage [scan_1=" + scan_1.getId() + ", scan_2=" + scan_2.getId() + "]";
}
}
一个测试类:TestScan.java
package com.xfwl.spring.annotation; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.xfwl.spring.annotation.scans.ComponScan_1;
import com.xfwl.spring.annotation.scans.ComponScan_2;
import com.xfwl.spring.annotation.scans.ScanManage;
import com.xfwl.spring.annotation.scans2.ScanManage2; public class TestScan {
//项目相对路径
private static final String xmlRelPath="com/xfwl/spring/assem/applicationContext.xml";
public static void main(String[] args) {
//通过注解拿到Spring IoC容器对象
/**
* ScanManage:使用了@ComponnetScan的basePackageClasses的配置项
* ScanManage2:使用了@ComponnetScan的basePackages的配置项
*/
20 //ApplicationContext ctx=new AnnotationConfigApplicationContext(ScanManage.class);//不可以把@ComponentScan注解在接口中,会报错
21 ApplicationContext ctx=new AnnotationConfigApplicationContext(ScanManage2.class);
//获取Bean对象
ComponScan_1 scan1_1=(ComponScan_1) ctx.getBean("scan_1");
System.out.println(scan1_1.toString());
ComponScan_2 scan1_2=(ComponScan_2) ctx.getBean("scan_2");
System.out.println(scan1_2.toString());
ScanManage scan1Manage1=(ScanManage) ctx.getBean("scanManage");
System.out.println(scan1Manage1.toString());
}
}
测试结果:以上加粗,红色的代码,均可以正常运行,说明注解正常在跑。
总结一下:
不可以把@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 注解普通属性字段:
package com.xfwl.spring.annotation; import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 注解测试:@Autoired 自动装配
* @function
* @author 小风微凉
* @time 2018-7-10 上午11:32:01
*/
@Component("manager")
public class Manager{
@Autowired
private long id;
@Autowired
private String mname;
@Autowired
private int mage;
/******getter和setter***********/
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public int getMage() {
return mage;
}
public void setMage(int mage) {
this.mage = mage;
}
}
@Autowired 注解引用类型字段:
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:55:26
*/
@Component("serviceImp")
//@Primary
public class ServiceImpl implements IServices {
@Autowired(required=true)
private UserBean user;
@Override
public void show() {
System.out.println(this.user.toString());
}
/**********getter和setter*******************/
public UserBean getUser() {
return user;
}
public void setUser(UserBean user) {
this.user = user;
}
}
正如之前所谈到的在默认情况下是必须注入成功的,所以这里的required的默认值为true。当把配置修改为false时,就告诉Spring IoC容器,假如在已经定义好的Bean中查找
不到的对应的类型,允许不注入,这样也就没有异常抛出,只是这个字段可能为空,开发者自行校验,以免发生空指针异常。在大部分情况下,都不需要这样修改。
@Autowired除可以配置在属性字段上外,还可以配置在方法上,常见的Bean的setter方法也可以使用它完成注入。
private UserBean user;
/**********getter和setter*******************/
@Autowired(required=true)
public void setUser(UserBean user) {
this.user = user;
}
在大部分配置中,推荐使用@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
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 测试注解:@Component装配Bean
* @author Jason
*
*/
@Component("user") //注入user //@Component("user")或者@Component(value="user")
public class UserBean {
@Value("xfww")
private String uname;
@Value("123456")
private String upwd;
public UserBean(){}
public UserBean(String uname,String upwd){
this.uname=uname;
this.upwd=upwd;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpwd() {
return upwd;
}
public void setUpwd(String upwd) {
this.upwd = upwd;
}
@Override
public String toString() {
return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
} }
接口:IServices.java
package com.xfwl.spring.annotation.qualifier; import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 服务接口:测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:52:29
*/
@Component(value="service")
public interface IServices {
public void show();
}
第一个实现子类:ServiceImpl.java
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:55:26
*/
@Component("serviceImp")
@Primary
public class ServiceImpl implements IServices {
@Autowired(required=true)
private UserBean user;
@Override
public void show() {
System.out.println(this.user.toString());
}
/**********getter和setter*******************/
public UserBean getUser() {
return user;
}
public void setUser(UserBean user) {
this.user = user;
}
}
第二个实现子类:ServiceImpl2.java(在此类中使用注解@Primary)
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:55:26
*/
@Component("serviceImp")
@Primary
public class ServiceImpl implements IServices {
@Autowired(required=true)
private UserBean user;
@Override
public void show() {
System.out.println(this.user.toString());
}
/**********getter和setter*******************/
public UserBean getUser() {
return user;
}
public void setUser(UserBean user) {
this.user = user;
}
}
在创建一个逻辑管理类:UserManage.java(在此类中添加注解扫描器)
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:58:56
*/
@Component("manager")
@ComponentScan(basePackages={"com.xfwl.spring.annotation.qualifier"})//启动扫描当前所在包的Bean,注入Spring IoC容器
public class UserManage {
@Autowired(required=true)
//@Qualifier("serviceImp2")
private IServices service; public void show(){
this.service.show();
}
/**********getter和setter*******************/
public IServices getService() {
return service;
}
public void setService(IServices service) {
this.service = service;
}
}
再来一个测试类:TestScan.java
package com.xfwl.spring.annotation.qualifier; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.xfwl.spring.annotation.scans.ComponScan_1;
import com.xfwl.spring.annotation.scans.ComponScan_2;
import com.xfwl.spring.annotation.scans.ScanManage;
import com.xfwl.spring.annotation.scans2.ScanManage2; public class TestScan {
//项目相对路径
private static final String xmlRelPath="com/xfwl/spring/assem/applicationContext.xml";
public static void main(String[] args) {
ApplicationContext ctx=new AnnotationConfigApplicationContext(UserManage.class);
//获取Bean对象
UserManage manager=(UserManage) ctx.getBean("manager");
manager.show();
}
}
测试结果:注解正常运行
第二种注解@Qualifier:
正如上面谈及到的歧义性,一个重要的原因是Spring在寻找依赖注入的时候采用按类型注入引起的。处理按照类型查找Bean,Spring IoC容器最底层的接口BeanFactory,
也定义了按照名称查找的方法,如果采用名称查找的方法,而不是采用类型查找,那么不就可以消除歧义性了吗?答案是肯定的!而注解@Qualifier就是这样一个注解。
测试代码如下:(由于注解@Primary和注解@Qualifier的测试代码及其相似,所以以下会修改上面的代码来完成测试)
修改ServiceImpl.java,修改部分如下:
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:55:26
*/
@Component("serviceImp")
//@Primary
public class ServiceImpl implements IServices {
@Autowired(required=true)
private UserBean user;
@Override
public void show() {
System.out.println(this.user.toString());
}
/**********getter和setter*******************/
public UserBean getUser() {
return user;
}
public void setUser(UserBean user) {
this.user = user;
}
}
在UserManage.java中指定:@Qualifier("serviceImp2")
package com.xfwl.spring.annotation.qualifier; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 测试注解@Qualifier
* @function
* @author 小风微凉
* @time 2018-7-12 上午11:58:56
*/
@Component("manager")
@ComponentScan(basePackages={"com.xfwl.spring.annotation.qualifier"})//启动扫描当前所在包的Bean,注入Spring IoC容器
public class UserManage {
@Autowired(required=true)
@Qualifier("serviceImp2")
private IServices service; public void show(){
this.service.show();
}
/**********getter和setter*******************/
public IServices getService() {
return service;
}
public void setService(IServices service) {
this.service = service;
}
}
测试结果:注解正常运行
5、装载带有参数的构造方法类:
贴出测试代码:
package com.xfwl.spring.annotation.qualifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("serviceImp")
public class ServiceImpl implements IServices {
private UserBean user;
public ServiceImpl(@Autowired UserBean user){//测试通过
this.user=user;
}
@Override
public void show() {
System.out.println(this.user.toString());
}
}
或者
package com.xfwl.spring.annotation.qualifier;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("serviceImp3")
public class ServiceImpl3 implements IServices {
private UserBean user;
public ServiceImpl3(@Qualifier UserBean user){//测试不通过,不支持注解@Qualifier注入构造器的参数
this.user=user;
}
@Override
public void show() {
System.out.println(this.user.toString());
}
}
从上面的代码,可以看出:这种注解并没有放在属性字段或者属性的setter方法上,而是直接放在构造器上的。
6、使用@Bean装配Bean
以上描述的用法都是通过@Componnet注解装配Bean,但是@Componnet只能注解在类上,不能注解在方法上。对于Java而言,大部分的开发都需要引入第三方的包(Jar文件),而且往往
并没有这些包的源码,这时候无法为这些包的类加入@Componnet注解,让他们变为开发环境的Bean.你可以使用新类扩展(extends)其包内的类,然后在新类上使用@Componnet,但是这样又显得
不伦不类。
这个时候Spring给与一个注解@Bean,它可以注解到方法上,并且讲方法返回的对象作为Spring的Bean存放在IoC容器中。比如我们需要用到的DBCP数据源。
现在来测试一下:
package com.xfwl.spring.annotation.bean; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; @ComponentScan(basePackages={"com.xfwl.spring.annotation.bean"})
public class ManagerScan {
@Bean(name="ds")
public DataSource getDataSource(){
Properties props=new Properties();
props.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
props.setProperty("url", "jdbc:oracle:thin:@***.**.17.33:1521:**");
props.setProperty("username", "***");
props.setProperty("password", "***");
DataSource dataSource=null;
try {
dataSource=BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
}
以及
package com.xfwl.spring.annotation.bean;
import java.util.Properties; import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
@Component("test")
public class TestBean {
public static void main(String[] args) {
//通过注解获取IoC容器对象
ApplicationContext ctx=new AnnotationConfigApplicationContext(ManagerScan.class);
System.out.println(ctx.getBean("ds").toString());
}
}
测试结果显示:可以从Spring IoC容器中拿到ds这个Bean对象。
7、注解自定义Bean的初始化和销毁方法:
注解@Bean不能使用在类的标注上,它主要使用在方法上,@Bean的配置项包含4个配置项:
- name:是一个字符串数组,允许配置多个BeanName。
- autowire:标志是否是一个引用的Bean对象,默认值是AutoWire.No。
- initKMethod:自定义初始化方法。
- destoryMethod:自定义销毁方法。
基于上面的描述,自定义初始化的方法是initMethod,销毁的方法则是destoryMethod。
贴出测试代码:
创建一个基本POJO类:UserBean.java (内置自定义的初始化和销毁方法)
package com.xfwl.spring.annotation.bean; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component; /**
* 测试注解:@Component装配Bean
* @author Jason
*
*/
@Component("user") //注入user //@Component("user")或者@Component(value="user")
public class UserBean {
@Value("xfww")
private String uname;
@Value("123456")
private String upwd;
public UserBean(){}
public UserBean(String uname,String upwd){
this.uname=uname;
this.upwd=upwd;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpwd() {
return upwd;
}
public void setUpwd(String upwd) {
this.upwd = upwd;
}
@Override
public String toString() {
return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
}
/**Bean生命周期测试**/
public void init(){
System.out.println("【"+this.getClass().getSimpleName()+"】执行自定义初始化方法!");
}
public void mydestory(){
System.out.println("【"+this.getClass().getSimpleName()+"】执行自定义销毁法!");
}
}
创建一个测试@Bean的类:(特别说明一下:注解@Configuration表示是告诉spring这个类是一个配置类,相当于我们的xml配置文件)
package com.xfwl.spring.annotation.bean; import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages={"com.xfwl.spring.annotation.bean"})
public class ManagerScan{
@Bean(name={"tom","jack"},initMethod="init",destroyMethod="mydestory")
public UserBean getUser(@Autowired UserBean user){
return user;
}
}
创建一个测试类:
package com.xfwl.spring.annotation.bean;
import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
@Component("test")
public class TestBean {
public static void main(String[] args) {
//通过注解获取IoC容器对象
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(ManagerScan.class);
UserBean user=(UserBean) ctx.getBean("tom");
System.out.println(user.toString());
ctx.close();
}
}
测试结果:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
【UserBean】执行自定义初始化方法!
UserBean [uname=xfww, upwd=123456]
【UserBean】执行自定义销毁法!