Spring-基于注解的配置[02自动装载bean](下)

简介: Spring-基于注解的配置[02自动装载bean](下)

小结


一般情况下,Spring容器中大部分的Bean是单实例的,所以一般无需通过@Repository、@Service等注解的value属性指定Bean的名称,也无须使用@Qualifier注解按照名称进行注入。


虽然Spring支持在属性和方法上标注自动注入注解@Autowired,但在实际项目开发中建议采用在方法上标注@Autowired,因为这样更加“面向对象”,也方便单元测试的编写, 如果将注解标注在私有属性上,则在单元测试的时候就很难用编程的办法设置属性值。


集合类进行标注


如果对类中集合类的变量或者方法入参进行@Autowired标注,那么Spring会将容器中类型所有匹配的Bean都自动注入进来。


实例


20170730040057922.jpg

接口 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));
        }
    }
}


运行结果:


20170730040348102.jpg


对延迟依赖注入的支持


Spring4.0支持延迟依赖注入,即在Spring容器的时候,对已在Bean上标注了@Lazy和@Autowired注解的属性,不会立即注入属性值。 而是延迟到调用此属性的时候才会注入属性值。


对于Bean实施延迟依赖注入,要注意@Lazy注解必须同时标注在属性及目标Bean上,二者缺一不可,否则延迟注入无效。


实例

20170730051725298.jpg


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");
    }
}


运行结果:

20170730051953511.jpg

我们可以看到,并没有实例化Plane这个Bean.

我们将@Lazy去掉,再次运行下


20170730052131503.jpg


可以看到 启动容器的时候,Plane bean已经被加载实例化了。


对标准注解的支持


Spring还支持JSR-250中定义的@Resource和JSR-330中定义的@Inject注解,这两个标准注解和@Autowired注解的功能类似,都能对类变更及方法入参提供自动注入功能。


@Resource注解要求提供一个Bean名称的属性,如果属性为空,则自动采用标注处的变量名或者方法名作为Bean的名称。


实例

20170730055833281.jpg

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();
    }
}


运行结果


20170730055933001.jpg


小结


如果@Resource未指定plane属性,则也可以根据属性方法得到需要注入的Bean名称。


@Autowired默认按照类型匹配注入bean, @Resource默认按照名称匹配注入Bean。而@Inject和@Autowired同样也是按照类型匹配注入Bean的,只不过它没有required属性。


可见不管是@Resource或者@Inject注解,其功能都没有@Autowired丰富,因此除非有不要,大可不必在乎这两个注解

相关文章
|
15天前
|
存储 Java 数据安全/隐私保护
|
5天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
1天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
1天前
|
安全 Java 开发者
深入理解Spring Boot配置绑定及其实战应用
【4月更文挑战第10天】本文详细探讨了Spring Boot中配置绑定的核心概念,并结合实战示例,展示了如何在项目中有效地使用这些技术来管理和绑定配置属性。
8 1
|
2天前
|
Java Spring
Spring文件配置以及获取
Spring文件配置以及获取
10 0
|
3天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
16 2
|
5天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
15 2
|
9天前
|
Java 微服务 Spring
Spring Boot中获取配置参数的几种方法
Spring Boot中获取配置参数的几种方法
20 2
|
11天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
19 1
|
11天前
|
Java Spring
springboot自带的@Scheduled注解开启定时任务
springboot自带的@Scheduled注解开启定时任务