Spring IOC中的annotation配置有好几种方式~最重要的分别是
@Component
@Resource
@Autowired
它们可以一起使用~
一,那就先说一下@Component如何使用的~
1 @Component注解可以直接定义bean,而无需在xml定义。但是若两种定义同时存在,xml中的定义会覆盖类中注解的Bean定义。
2 @Component注解直接写在类上面即可
3 @Component有一个可选的参数,用于指定 bean 的名称:如@Component("boss")
4 @Component容易不指定参数,则 bean 的名称为当前类的类名小写
5 @Component使用之后需要在xml文件配置一个标签: <context:component-scan/>
6 <context:component-scan base-package="com.briup.ioc.annotation" /> 可以表示spring需要检查哪个包下的java类,看它们是否使用了 @Component注解
7 @Component定义的bean默认情况下都是单例模式的,如果要让这个bean变为非单例,可以再结合这个 @Scope 注解来达到目标 @Scope("prototype")
@Component是Spring中所有bean组件的通用形式, @Repository @Service @Controller 则是 @Component的细化,用来表示更具体的用例,分别对应了持久化层、服务层和表现层。但是至少到现在为止这个四种注解的实质区别很小(甚至几乎没有),都是把当前类注册为spring容器中的一个bean。
看个例子:
Boss类:
//相当于配置文件中的<bean name="boss" class="...." ></bean>
<span style="color:#ff0000;">@Scope("prototype")
@Component("boss")</span>
public class Boss {
private String name;
private Car car;
private Office office;
public Boss(){
}
public Boss(String name, Car car, Office office) {
this.name = name;
this.car = car;
this.office = office;
}
public Boss(Car car, Office office) {
this.car = car;
this.office = office;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Office getOffice() {
return office;
}
public void setOffice(Office office) {
this.office = office;
}
public void init(){
System.out.println("初始化..");
}
public void destroy(){
System.out.println("销毁");
}
}
Office类:
<span style="color:#ff0000;">@Component("office")</span>
public class Office {
private String num = "001";
public Office(){
}
public Office(String num) {
this.num = num;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
}
Car类:
<span style="color:#ff0000;">@Component("car")</span>
public class Car {
private String name;
private double price;
public Car(){
}
public Car(double price, String name) {
this.price = price;
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
三个Bean类都使用了@Component来直接定义bean,在看配置文件annotation.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<span style="color:#ff0000;"> <!-- 告诉Spring容器要扫描哪些包 -->
<context:component-scan base-package="com.x.spring.test3.annotation" /></span>
<bean name="car" class="com.x.spring.test3.annotation.Car">
<property name="name" value="BMW"></property>
</bean>
<bean name="car2" class="com.x.spring.test3.annotation.Car">
<property name="name" value="Auto"></property>
</bean>
<bean name="office" class="com.x.spring.test3.annotation.Office">
<property name="name" value="BEN"></property>
</bean>
</beans>
在这个配置文件中又重新定义了bean,所以用了注释的Bean类要以配置文件为准~
测试类:
public class AnnotationTest {
public static void main(String[] args) {
//ioc中的注解
try {
String path = "com/x/spring/test3/annotation/annotation.xml";
ClassPathXmlApplicationContext container =
new ClassPathXmlApplicationContext(path);
Boss boss = (Boss)container.getBean("boss");
} catch (Exception e) {
e.printStackTrace();
}
}
}
效果图就不贴了~
还可以@Component与@PostConstruct 和 @PreDestroy一起使用~
@PostConstruct 和 @PreDestroy
1 标注了 @PostConstruct 注释的方法将在类实例化后调用。
2 标注了 @PreDestroy 的方法将在类销毁之前调用。
这俩个注释就相当于bean对象的初始化和销毁~
在Boss类加上几行代码,如图:
在测试类加上这行代码:
container.destroy();
看看效果:
效果图果然如我所料,因为Boss类已经是非单例管理的对象了~所以对象的销毁Spring容器管不着~
那接下来就看看@Autowired~
二,@Autowired(与@Component)的使用
1 @Autowired默认按照byType匹配的方式进行注入,如果没有一个bean的类型是匹配的则会抛异常,
如果有多个bean的类型都匹配成功了,那么再按byName方式进行选择
2 @Autowired注解可以写在成员变量、set/ger方法、构造器函数上面
3 @Autowired如果最终匹配不成功(注意一定是一个都没有找到的情况)则会抛出异常,
但是如果设置为@Autowired(required=false),则最终匹配不成功没有不会抛出异常。
4 @Autowired可以结合 @Qualifier("beanName")来使用,则可以达到byName的效果
5 @Autowired使用后需要在xml文件加入以下配置才能生效:
<context:annotation-config/>
不懂byType和byName自动注入的可以去看我的这篇:Spring IOC注入(注入)自动注入
先分析一下@Autowired注解写在成员变量上面:
在Boss类加上这一行代码:
就可以把car对象自动注入进来,因为xml文件有2个car对象,就会按照byName的方式把这个对象自动注入进来,如图:
测试类也加了几行代码:
System.out.println(boss.getCar());
System.out.println(boss.getCar().getName());
效果图如下:
再分析把@Autowired注解写在set/get方法上面
效果图跟放在成员变量上面是一样的~
再分析把@Autowired注解写在构造器函数上面
效果图是一样的~
其他的情况我就不一一贴代码了~仔细想想就很容易明白
我们再来分析@Resource吧
三,@Resource(与@Component)的使用
1 @Resource的作用和 @Autowired差不多,只不过@Resource是默认先用byname,
如果找不到合适的就再用bytype来注入
2 @Resource有俩个属性,name和type,使用name属性则表示要byName匹配,使用type属性则表示要byType匹配
3 @Resource使用后需要在xml文件加入以下配置才能生效:
<context:annotation-config/>
在Boss类简单的使用一下这个@Resource吧,如图,添加了这一行代码:
这个@Resource默认使用byName方式来进行自动注入的~
在测试类中也加入几行代码:
System.out.println(boss.getOffice());
System.out.println(boss.getOffice().getNum());
测试效果如下:
好了,这个注解方式就这样简单~
完整代码如下:
测试类:
public class AnnotationTest {
public static void main(String[] args) {
//ioc中的注解
try {
String path = "com/x/spring/test3/annotation/annotation.xml";
ClassPathXmlApplicationContext container =
new ClassPathXmlApplicationContext(path);
Boss boss = (Boss)container.getBean("boss");
System.out.println(boss);
System.out.println(boss.getCar());
System.out.println(boss.getCar().getName());
System.out.println(boss.getOffice());
System.out.println(boss.getOffice().getNum());
//这行代码在这没用,因为Boss类是非单例管理对象
container.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Boss类:
//相当于配置文件中的<bean name="boss" class="...." ></bean>
@Scope("prototype")
@Component("boss")
public class Boss {
private String name;
@Autowired
private Car car;
@Resource
private Office office;
public Boss(){
}
public Boss(String name, Car car, Office office) {
this.name = name;
this.car = car;
this.office = office;
}
//@Autowired
public Boss(Car car, Office office) {
this.car = car;
this.office = office;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
//@Autowired
public void setCar(Car car) {
this.car = car;
}
public Office getOffice() {
return office;
}
public void setOffice(Office office) {
this.office = office;
}
@PostConstruct
public void init(){
System.out.println("初始化..");
}
@PreDestroy
public void destroy(){
System.out.println("销毁");
}
}
Office类:
@Component("office")
public class Office {
private String num = "001";
public Office(){
}
public Office(String num) {
this.num = num;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
}
Car类:
@Component("car")
public class Car {
private String name;
private double price;
public Car(){
}
public Car(double price, String name) {
this.price = price;
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- 告诉Spring容器要扫描哪些包 -->
<context:component-scan base-package="com.x.spring.test3.annotation" />
<bean name="car" class="com.x.spring.test3.annotation.Car">
<property name="name" value="BMW"></property>
</bean>
<bean name="car2" class="com.x.spring.test3.annotation.Car">
<property name="name" value="Auto"></property>
</bean>
<bean name="office" class="com.x.spring.test3.annotation.Office">
<property name="num" value="123"></property>
</bean>
</beans>
最后要注意一点:
component-scan标签默认情况下自动扫描指定路径下的包(含所有子包),将带有 @Component @Repository @Service @Controller标签的类自动注册到spring容器。对标记了 Spring中的 @Required @Autowired @PostConstruct @PreDestroy @Resource @WebServiceRef @EJB @PersistenceContext @PersistenceUnit等注解的类进行对应的操作使注解生效(包含了annotation-config标签的作用)