- 使用Autowired进行自动注入
- 实例
- 使用Auotwired的required属性
- 实例
- 使用Qualifier指定注入Bean的名称
- 实例
- 对类方法进行标注
- 实例
- 小结
- 对集合类进行标注
- 实例
- 对延迟依赖注入的支持
- 实例
- 对标准注解的支持
- 实例
- 小结
使用@Autowired进行自动注入
Spring通过@Autowired注解实现Bean的依赖注入。
@Autowired默认按照类型(byType)匹配的方式在容器中查找匹配的Bean,当且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
代码语言:javascript复制import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Pilot {
@Autowired
private Plane plane;
public void drivePlane() {
plane.fly();
}
}
实例
POJO类
代码语言:javascript复制package com.xgj.ioc.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Pilot {
@Autowired
private Plane plane;
public void drivePlane() {
plane.fly();
}
}
@Component注解将Pilot标注为一个Bean,Spring会扫描加载并实例化该Bean。
通过@Autowired注入plan的Bean。
POJO类
代码语言:javascript复制package com.xgj.ioc.configuration;
import org.springframework.stereotype.Component;
@Component
public class Plane {
private String brand;
private String color;
private int speed;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void introduce() {
System.out.println("Plane information【 brand:" brand ",color:"
color ",speed:" speed);
}
public void fly() {
System.out.println("Plane begins to fly");
}
}
配置文件
代码语言:javascript复制<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xgj.ioc.configuration"/>
beans>
测试类
代码语言:javascript复制package com.xgj.ioc.configuration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ConfigBeanTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/ioc/configuration/beans.xml");
Pilot pilot = ctx.getBean("pilot", Pilot.class);
pilot.drivePlane();
Plane plane = ctx.getBean("plane", Plane.class);
plane.setBrand("A380");
plane.setColor("White");
plane.setSpeed(800);
plane.introduce();
}
}
运行结果:
使用@Auotwired的required属性
如果容器中没有一个和标注变量类型匹配的Bean,那么Spring启动的时候会报NoSuchBeanDefinitionException异常。 如果希望Spring及时找不到匹配的Bean完成注入也不要抛出异常,那么就可以使用@Autowired(required=false)进行标注。
实例
还是以上面的例子为基础改造下,我们知道上面的扫描包配置的为
代码语言:javascript复制<context:component-scan base-package="com.xgj.ioc.configuration"/>
假设在com.xgj.ioc.configuration之外的包目录下 有个Tank类(com.xgj.ioc.inject.construct.type.Tank)
改造下Pilot类,引入Tank,设置自动注入
代码语言:javascript复制package com.xgj.ioc.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xgj.ioc.inject.construct.type.Tank;
@Component
public class Pilot {
@Autowired
private Plane plane;
@Autowired
private Tank tank;
public void drivePlane() {
plane.fly();
}
}
@Autowired 默认 required =true
运行测试类:
代码语言:javascript复制No qualifying bean of type 'com.xgj.ioc.inject.construct.type.Tank' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
我们改造下@Autowired(required = false)
代码语言:javascript复制@Autowired(required = false)
private Tank tank;
再此运行: OK
使用@Qualifier指定注入Bean的名称
如果容器中有一个以上匹配的Bean时,则可以通过@Qualifier注解限定Bean的名称。
假设容器中有两个类型为Plane的Bean,一个名为plane,一个名为otherPlane. 因为@Autowired默认是按照类型匹配的方式在容器中查找,plane和otherPlane的类型都是Plane,怎么知道注入哪一个呢?
实例
我们在扫描的基类包下增加个子包 other,包下新增同名Plane类,通过@Component(“otherPlane”)指定Bean的名称。
com.xgj.ioc.configuration.other.Plane代码如下:
代码语言:javascript复制package com.xgj.ioc.configuration.other;
import org.springframework.stereotype.Component;
@Component("otherPlane")
public class Plane {
private String brand;
private String color;
private int speed;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void introduce() {
System.out.println("OtherPlane information【 brand:" brand ",color:"
color ",speed:" speed);
}
public void fly() {
System.out.println("OtherPlane begins to fly");
}
}
如果我们希望注入otherPlane呢?
我们来改造Pilot类
代码语言:javascript复制package com.xgj.ioc.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
// 1. 引入其他子包下的Plane
import com.xgj.ioc.configuration.other.Plane;
import com.xgj.ioc.inject.construct.type.Tank;
@Component
public class Pilot {
@Autowired
// 2 通过@Qualifier限定Bean的名称
@Qualifier("otherPlane")
private Plane plane;
@Autowired(required = false)
private Tank tank;
public void drivePlane() {
plane.fly();
}
}
测试类中改动的地方
记得引入 other子包下的Plane
代码语言:javascript复制import com.xgj.ioc.configuration.other.Plane;
.....
Plane plane = ctx.getBean("otherPlane", Plane.class);
然后运行测试类:
对类方法进行标注
@Autowired可以对类成员变量以及方法的入参进行标注。
下面在类的方法上使用@Autowired注解。
实例
代码语言:javascript复制package com.xgj.ioc.configuration.method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Pilot {
private Plane plane;
// 自动将Plane类型传给方法入参
@Autowired
public void setPlane(Plane plane) {
this.plane = plane;
}
public void drivePlane() {
plane.fly();
}
}
如果是下面这种写法
代码语言:javascript复制 // 自动将名为plane的Bean传给方法入参
@Autowired
@Qualifier("plane")
public void setPlane(Plane plane) {
this.plane = plane点内容**
如果一个方法拥有多个入参,在默认情况下,Spring将自动选择匹配入参类型的Bean进行注入。 Spring允许对方法入参标注@Qualifier以指定注入Bean的名称。
比如
代码语言:javascript复制@Autowired
public void setPlane(Plane plane, @Qualifier("tank") Tank tank) {
this.plane = plane;
}
在这种情况下,Plane的入参注入为Plane类型的Bean,而Tank的入参注入的则为名称为tank的Bean.
实例代码如下:
Pilot POJO类
代码语言:javascript复制package com.xgj.ioc.configuration.method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Pilot {
private Plane plane;
// 自动将Plane类型传给方法入参
@Autowired
public void setPlane(Plane plane) {
this.plane = plane;
}
public void drivePlane() {
plane.fly();
}
}
Plane POJO类
代码语言:javascript复制package com.xgj.ioc.configuration.method;
import org.springframework.stereotype.Component;
@Component // 通过注解标注为一个Bean,以便Spring扫描并实例化
public class Plane {
public void fly() {
System.out.println("Plane begins to fly");
}
}
配置文件
代码语言:javascript复制<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xgj.ioc.configuration.method"/>
beans>
测试类
代码语言:javascript复制package com.xgj.ioc.configuration.method;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ConfigMethodTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/ioc/configuration/method/beans.xml");
Pilot pilot = ctx.getBean("pilot", Pilot.class);
pilot.drivePlane();
}
}
运行结果
小结
一般情况下,Spring容器中大部分的Bean是单实例的,所以一般无需通过@Repository、@Service等注解的value属性指定Bean的名称,也无须使用@Qualifier注解按照名称进行注入。
虽然Spring支持在属性和方法上标注自动注入注解@Autowired,但在实际项目开发中建议采用在方法上标注@Autowired,因为这样更加“面向对象”,也方便单元测试的编写, 如果将注解标注在私有属性上,则在单元测试的时候就很难用编程的办法设置属性值。
对集合类进行标注
如果对类中集合类的变量或者方法入参进行@Autowired标注,那么Spring会将容器中类型所有匹配的Bean都自动注入进来。
实例
接口 Plugin
代码语言:javascript复制package com.xgj.ioc.configuration.lstmpSupport;
public interface Plugin {
}
POJO
代码语言:javascript复制package com.xgj.ioc.configuration.lstmpSupport;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value = 1)
public class Plugin1 implements Plugin {
/**
*
*
* @Title:Plugin1
*
* @Description:构造函数
*/
public Plugin1() {
super();
System.out.println("Pligin1 Init");
}
}
POJO
代码语言:javascript复制package com.xgj.ioc.configuration.lstmpSupport;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value = 2)
public class Plugin2 implements Plugin {
/**
*
* @Title:Plugin2
*
* @Description:构造函数
*
* */
public Plugin2() {
super();
System.out.println("Pligin2 Init");
}
}
通过@Component标注为Bean,Spring会将 Plugin1和Plugin2这两个Bean都注入到plugins中。 在默认情况下,这两个bean的加载顺序是不确定,在Spring4.0中可以通过@Order注解或者实现Ordered接口来决定Bean加载的顺序,值越小,优先被加载。
POJO
代码语言:javascript复制package com.xgj.ioc.configuration.lstmpSupport;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
private List plugins;
private Map pluginMap;
// Spring会将容器中所有类型为Plugin的Bean注入到这个变量中
@Autowired(required = false)
public void setPlugins(List plugins) {
this.plugins = plugins;
}
// 将Plugin类型的Bean注入到Map中
@Autowired
public void setPluginMap(Map pluginMap) {
this.pluginMap = pluginMap;
}
/**
*
*
* @Title: getPlugins
*
* @Description: 获取Plugins
*
* @return
*
* @return: List
*/
public List getPlugins() {
return plugins;
}
/**
*
*
* @Title: getPluginMap
*
* @Description: 获取Map
*
* @return
*
* @return: Map
*/
public Map getPluginMap() {
return pluginMap;
}
}
Spring如果发现变量是一个List和一个Map的集合类,则它会将容器中匹配集合元素类型的所有Bean都注入进来。
private Map
代码语言:javascript复制<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xgj.ioc.configuration.lstmpSupport"/>
beans>
测试类:
代码语言:javascript复制package com.xgj.ioc.configuration.lstmpSupport;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ListMapSupportTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/ioc/configuration/lstmpSupport/beans.xml");
// 从容器中获取bean
MyComponent myComponent = ctx.getBean("myComponent", MyComponent.class);
// 获取Map集合
Map map = myComponent.getPluginMap();
// Map遍历key和value
for (Entry entry : map.entrySet()) {
System.out.println("key:" entry.getKey());
System.out.println("value:" entry.getValue());
}
// 获取list集合
List list = myComponent.getPlugins();
// 遍历list
for (int i = 0; i < list.size(); i ) {
System.out.println("list中的元素" i "为" list.get(i));
}
}
}
运行结果:
对延迟依赖注入的支持
Spring4.0支持延迟依赖注入,即在Spring容器的时候,对已在Bean上标注了@Lazy和@Autowired注解的属性,不会立即注入属性值。 而是延迟到调用此属性的时候才会注入属性值。
对于Bean实施延迟依赖注入,要注意@Lazy注解必须同时标注在属性及目标Bean上,二者缺一不可,否则延迟注入无效。
实例
代码语言:javascript复制package com.xgj.ioc.configuration.lazyLoad;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
public class Pilot {
private Plane plane;
// 延迟注入
@Lazy
@Autowired(required = false)
public void setPlane(Plane plane) {
this.plane = plane;
}
}
POJO
代码语言:javascript复制package com.xgj.ioc.configuration.lazyLoad;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Lazy
// @Lazy 目标Bean 延迟注入
@Component
// 通过注解标注为一个Bean,以便Spring扫描并实例化
public class Plane {
/**
*
*
* @Title:Plane
*
* @Description:无参构造函数
*/
public Plane() {
super();
System.out.println("Plan init ");
}
public void fly() {
System.out.println("Plane begins to fly");
}
}
配置文件:
代码语言:javascript复制<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xgj.ioc.configuration.lazyLoad"/>
beans>
测试
代码语言:javascript复制package com.xgj.ioc.configuration.lazyLoad;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LazyLoadTest {
public static void main(String[] args) {
// 初始化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/ioc/configuration/lazyLoad/beans.xml");
}
}
运行结果:
我们可以看到,并没有实例化Plane这个Bean.
我们将@Lazy去掉,再次运行下
可以看到 启动容器的时候,Plane bean已经被加载实例化了。
对标准注解的支持
Spring还支持JSR-250中定义的@Resource和JSR-330中定义的@Inject注解,这两个标准注解和@Autowired注解的功能类似,都能对类变更及方法入参提供自动注入功能。
@Resource注解要求提供一个Bean名称的属性,如果属性为空,则自动采用标注处的变量名或者方法名作为Bean的名称。
实例
POJO
代码语言:javascript复制package com.xgj.ioc.configuration.standard;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class Pilot {
private Plane plane;
@Resource(name = "plane")
public void setPlane(Plane plane) {
this.plane = plane;
}
public void drivePlane() {
plane.fly();
}
}
POJO
代码语言:javascript复制package com.xgj.ioc.configuration.standard;
import org.springframework.stereotype.Component;
@Component
public class Plane {
public void fly() {
System.out.println("plane begins to fly");
}
}
配置文件
代码语言:javascript复制<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xgj.ioc.configuration.standard"/>
beans>
测试类
代码语言:javascript复制package com.xgj.ioc.configuration.standard;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StandardTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/ioc/configuration/standard/beans.xml");
ctx.getBean("pilot", Pilot.class).drivePlane();
}
}
运行结果
小结
如果@Resource未指定plane属性,则也可以根据属性方法得到需要注入的Bean名称。
@Autowired默认按照类型匹配注入bean, @Resource默认按照名称匹配注入Bean。而@Inject和@Autowired同样也是按照类型匹配注入Bean的,只不过它没有required属性。
可见不管是@Resource或者@Inject注解,其功能都没有@Autowired丰富,因此除非有不要,大可不必在乎这两个注解