小结
一般情况下,Spring容器中大部分的Bean是单实例的,所以一般无需通过@Repository、@Service等注解的value属性指定Bean的名称,也无须使用@Qualifier注解按照名称进行注入。
虽然Spring支持在属性和方法上标注自动注入注解@Autowired,但在实际项目开发中建议采用在方法上标注@Autowired,因为这样更加“面向对象”,也方便单元测试的编写, 如果将注解标注在私有属性上,则在单元测试的时候就很难用编程的办法设置属性值。
对集合类进行标注
如果对类中集合类的变量或者方法入参进行@Autowired标注,那么Spring会将容器中类型所有匹配的Bean都自动注入进来。
实例
接口 Plugin
package com.xgj.ioc.configuration.lstmpSupport; public interface Plugin { }
POJO
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
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
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<Plugin> plugins; private Map<String, Plugin> pluginMap; // Spring会将容器中所有类型为Plugin的Bean注入到这个变量中 @Autowired(required = false) public void setPlugins(List<Plugin> plugins) { this.plugins = plugins; } // 将Plugin类型的Bean注入到Map中 @Autowired public void setPluginMap(Map<String, Plugin> pluginMap) { this.pluginMap = pluginMap; } /** * * * @Title: getPlugins * * @Description: 获取Plugins * * @return * * @return: List<Plugin> */ public List<Plugin> getPlugins() { return plugins; } /** * * * @Title: getPluginMap * * @Description: 获取Map * * @return * * @return: Map<String,Plugin> */ public Map<String, Plugin> getPluginMap() { return pluginMap; } }
Spring如果发现变量是一个List和一个Map的集合类,则它会将容器中匹配集合元素类型的所有Bean都注入进来。
private Map
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- (1)声明Context命名空间以及Schema文件 (2)扫描类包以及应用注解定义的bean --> <context:component-scan base-package="com.xgj.ioc.configuration.lstmpSupport"/> </beans>
测试类:
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<String, Plugin> map = myComponent.getPluginMap(); // Map遍历key和value for (Entry<String, Plugin> entry : map.entrySet()) { System.out.println("key:" + entry.getKey()); System.out.println("value:" + entry.getValue()); } // 获取list集合 List<Plugin> 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上,二者缺一不可,否则延迟注入无效。
实例
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
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"); } }
配置文件:
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- (1)声明Context命名空间以及Schema文件 (2)扫描类包以及应用注解定义的bean --> <context:component-scan base-package="com.xgj.ioc.configuration.lazyLoad"/> </beans>
测试
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
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
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"); } }
配置文件
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- (1)声明Context命名空间以及Schema文件 (2)扫描类包以及应用注解定义的bean --> <context:component-scan base-package="com.xgj.ioc.configuration.standard"/> </beans>
测试类
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丰富,因此除非有不要,大可不必在乎这两个注解