1.xml中配置bean
假如我们现在有3个类,Boss、Office、Car,这3个类需要在Spring容器中配置为bean
public class Office {
private String officeNo =”001”;
//省略 get/setter
@Override
public String toString() {
return "officeNo:" + officeNo;
}
}
public class Car {
private String brand;
private double price;
// 省略 get/setter
@Override
public String toString() {
return "brand:" + brand + "," + "price:" + price;
}
}
public class Boss {
private Car car;
private Office office;
// 省略 get/setter
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
现在在beans.xml中将以上3个类配置成bean
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="boss" class="com.baobaotao.Boss">
<property name="car" ref="car"/>
<property name="office" ref="office" />
</bean>
<bean id="office" class="com.baobaotao.Office">
<property name="officeNo" value="002"/>
</bean>
<bean id="car" class="com.baobaotao.Car" scope="singleton">
<property name="brand" value=" 红旗 CA72"/>
<property name="price" value="2000"/>
</bean>
</beans>
这样的话就完成了依赖注入。
测试代码如下:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnoIoCTest {
public static void main(String[] args) {
String[] locations = {"beans.xml"};
ApplicationContext ctx =
new ClassPathXmlApplicationContext(locations);
Boss boss = (Boss) ctx.getBean("boss");
System.out.println(boss);
}
}
控制台正确打出了Boss的信息,说明Spring已经正确完成了实例的注入
2.@Autowired
(1)要求
Spring通过一个BeanPostProcessor对@Autowired进行解析,要使@Autowired起作用,则必须在Spring容器中声明AutowiredAnnotationBeanPostProcessor的Bean
<!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
这样,当Spring容器启动时,AutowiredAnnotationBeanPostProcessor将扫描Spring中的所有bean,如果发现bean中拥有@Autowired注解时,就找到何其匹配(
默认按类型匹配)的bean,并注入到对应的地方中去。
如果是在成员变量上使用的话:因为是直接使用反射对bean中的私有成员变量进行注入的,所以使用了@Autowired注解之后,可以直接删除setter方法
(2)成员变量上使用
public class Boss {
@Autowired
private Car car;
@Autowired
private Office office;
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="boss" class="com.mycompany.app.Boss">
</bean>
<bean id="office" class="com.mycompany.app.Office">
<property name="officeNo" value="002"/>
</bean>
<bean id="car" class="com.mycompany.app.Car" scope="singleton">
<property name="brand" value=" 红旗 CA72"/>
<property name="price" value="2000"/>
</bean>
</beans>
结果为:
car:brand: 红旗 CA72,price:2000.0
office:officeNo:002
(3)set方法上使用
package com.mycompany.app;
import org.springframework.beans.factory.annotation.Autowired;
public class Boss {
private Car car;
private Office office;
@Autowired
public void setCar(Car car) {
this.car = car;
}
@Autowired
public void setOffice(Office office) {
this.office = office;
}
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
这时,@Autowired将查找被标注的方法的传入参数类型的bean,并调用方法自动注入这些bean
(4)构造方法上使用
package com.mycompany.app;
import org.springframework.beans.factory.annotation.Autowired;
public class Boss {
private Car car;
private Office office;
@Autowired
public Boss(Car car, Office office) {
super();
this.car = car;
this.office = office;
}
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
由于Boss构造方法有两个入参,分别是car和office,@Autowired将分别寻找和他们类型匹配的bean,将他们作为入参来创建Boss bean
3.@Qualifier
(1)引入及作用
当我们在Spring容器中配置了2个类型为Office类型的bean,当对Boss的office成员变量进行自动注入时,Spring容器将无法确定到底使用哪一个bean,就会发生异常。
<bean id="boss" class="com.mycompany.app.Boss">
</bean>
<bean id="office1" class="com.mycompany.app.Office">
<property name="officeNo" value="002"/>
</bean>
<bean id="office2" class="com.mycompany.app.Office">
<property name="officeNo" value="004"/>
</bean>
运行后抛出异常
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.mycompany.app.Office] is defined: expected single matching bean but found 2: [office1, office2]
Spring中允许我们通过@Qualifier注释指定注入bean的名称,这样歧义就消除了,可以通过如下方法解决异常
package com.mycompany.app;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Boss {
@Autowired
private Car car;
@Autowired
@Qualifier("office1")
private Office office;
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
4.@Resource
(1)作用
@Resource作用相当于@Autowired,只不过 @Autowired按byType自动注入,@Resource按byName自动注入。@Resource有两个比较重要的属性:name和type,Spring将@Resource注释的name属性解析为bean的名字,而type属性解析为bean的类型。
所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果不指定name和type,则将通过反射来使用byName自动注入
(2)使用要求
1)@Resource位于common-annotation.jar中,因此在使用之前必须要导包2)在配置文件中加入:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
(3)例子
public class Boss {
@Resource
private Car car;
@Resource
private Office office;
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
5.spring中隐式注册注解
使用这些注解时需要在配置文件中导入很多配置,这样会导致配置文件混乱,所以spring提供了一个方法,可以隐式注册这些annotation
<context:annotation-config/>
但是需要导入context命名空间,所以,需要再加入context明明空间。整体配置如下:
<?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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="boss" class="com.mycompany.app.Boss">
</bean>
<bean id="office" class="com.mycompany.app.Office">
<property name="officeNo" value="002"/>
</bean>
<bean id="office2" class="com.mycompany.app.Office">
<property name="officeNo" value="004"/>
</bean>
<bean id="car" class="com.mycompany.app.Car" scope="singleton">
<property name="brand" value=" 红旗 CA72"/>
<property name="price" value="2000"/>
</bean>
</beans>
这个隐式配置实际上注册了4个类:
AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及equiredAnnotationBeanPostProcessor
6.@Component
(1)引入
虽然我们可以通过@Autowired或者@Resource在bean类中使用自动注入功能,但是bean还是在xml文件中通过<bean>进行了定义——也就是说,在xml配置文件中定义bean,通过@Autowired或者@Resource为bean的成员变量、方法、构造方法入参提供自动注入的功能。那么能否也通过注释定义bean,从xml配置中完全移除bean定义的配置呢?答案是肯定的。我们通过@Component注解就可以达到这个目标了。
实际上共有四种注解实现了这种功能@Component、@Repository、@Controller、@Service,功能完全相同,只是应用于不同的层次
@Component:是一个泛化的概念,仅仅表示是一个bean,可以用在任何层次
@Service:通常用在业务层,功能与@Component相同
@Controller:通常用在控制层,功能与@Component相同
@Repository:通常用在dao层,功能与@Component相同
(2)配置
1)需要指定扫描的包,这样的话spring就可以自动扫描指定包下带@Component(或其他三个)注解的类,并生成bean
<context:component-scan base-package="com.mycompany.app"/>
2)需要添加命名空间
<?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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
(3)实例
package com.mycompany.app;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class Boss {
@Resource
private Car car;
@Resource
private Office office;
@Override
public String toString() {
return "car:" + car + "\n" + "office:" + office;
}
}
car类
package com.mycompany.app;
import org.springframework.stereotype.Component;
@Component
public class Car {
private String brand = "红旗 CA72";
private double price = 2000;
@Override
public String toString() {
return "brand:" + brand + "," + "price:" + price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
注意:这里因为不能再在bean中指定car属性的值了,所以直接给成员变量赋值
package com.mycompany.app;
import org.springframework.stereotype.Component;
@Component
public class Office {
private String officeNo ="001";
public String getOfficeNo() {
return officeNo;
}
public void setOfficeNo(String officeNo) {
this.officeNo = officeNo;
}
@Override
public String toString() {
return "officeNo:" + officeNo;
}
}
(4)@Scope
@Scope注解可以和@Component注解配合使用,用来指定bean的scope。
默认是singleton,也就是整个应用使用同一个实例;如果使用prototype,则spring每次getBean都会拿到新的bean