跳至主要內容

依赖注入(IOC和DI)

wangdx大约 41 分钟

Ioc 的设计思想就是在于控制反转,也就是说将整个对象的实例化的处理操作全部交给容器完成,用户只需要通过容器获取一个对象的 Bean 就可以。而 IOC 基础上还有一个 DI(依赖注入) 的处理支持

Bean 的依赖注入

消息服务关联定义

  • 不同的 Bean 实例之间可以依靠引用来实现关联,在传统的 Java 项目开发中,都是在应用程序内依靠 Setter 方法调用的形式处理的,但是在 Spring 之中,这一切的引用结构都可以基于 XML 文件配置实现
1、
package com.yootk.di.config;

public class MessageConfig { // 定义消息数据的配置类
    private String host;
    private int port;
    private boolean enable;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}


2、
package com.yootk.di.type;

public enum MessageSendStatus { // 定义枚举类型
    SUCCESS, FAILURE; // 消息的发送状态
}


3、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    private MessageConfig config; // 这个类的执行需要config属性支持
    private boolean connect() { // 定义一个连接方法
        LOGGER.info("连接服务器:{}:{}", this.config.getHost(), this.config.getPort());
        return this.config.isEnable(); // 通过enable的状态来决定是否连接成功
    }
    public MessageSendStatus send(String msg) { // 消息发送
        if (this.connect()) {   // 消息发送之前需要首先连接服务器
            LOGGER.info("【消息发送】{}", msg); // 日志记录
            try {
                this.close(); // 关闭通道
            } catch (Exception e) {
                LOGGER.error("消息发送产生异常:{}", e.getMessage());
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        }
        LOGGER.error("无法创建消息发送通道,消息发送失败。");
        return MessageSendStatus.FAILURE; // 返回失败的状态
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理
    public void setConfig(MessageConfig config) { // 外部注入config实例
        this.config = config;
    }
    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


4、
<?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.xsd">
    <!--  定义消息通道的配置Bean,这个Bean需要进行属性的配置  -->
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="8869"/> <!-- 配置Bean属性 -->
        <!--  如果现在属性的类型是Boolean,那么除了使用true和false之外,Spring也有扩展  -->
        <!--  0(false)和1(true)、off(false)和on(true)组合  -->
        <property name="enable" value="on"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="config" ref="config"/> <!-- 引用关系的配置 -->
    </bean>
</beans>

5、
package com.yootk.test;

import com.yootk.di.service.MessageService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

// 表示要进行Spring配置文件的加载,后续也可能是进行配置类的加载
@ContextConfiguration(locations = {"classpath:spring/spring-base.xml"}) // 定义XML配置文件
@ExtendWith(SpringExtension.class) // 表示此时使用外部的测试工具(JUnit5)
public class TestMessageServiceTwo {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(TestMessageServiceTwo.class) ;// 获取日志实例
    @Autowired // 自动注入接口实例
    private MessageService messageService; // 要使用的业务接口
    @Test
    public void testSend() {
        this.messageService.send("沐言科技:www.yootk.com"); // 调用业务方法
    }
}

使用 p 命名空间实现依赖注入

p 命名空间

- p 命名空间在使用时需要结合“<bean>元素配置完成,而在配置时可以采用“p:属性名称=内容”的形式为指定的属性赋值,在设置引用关联时可以采用“p:属性名称-ref=引用 Bean 名称”的方式进行定义,下面的范例演示了 p 命名空间的具体应用
1、
    <!--  定义消息通道的配置Bean,这个Bean需要进行属性的配置  -->
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="8869"/> <!-- 配置Bean属性 -->
        <!--  如果现在属性的类型是Boolean,那么除了使用true和false之外,Spring也有扩展  -->
        <!--  0(false)和1(true)、off(false)和on(true)组合  -->
        <property name="enable" value="0"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="config" ref="config"/> <!-- 引用关系的配置 -->
    </bean>

2、

    <bean id="config" class="com.yootk.di.config.MessageConfig" p:host="message.yootk.com" p:port="8869" p:enable="off"/>
    <bean id="messageService" class="com.yootk.di.service.MessageService" p:config-ref="config"/>

构造方法注入

1、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    private MessageConfig config; // 这个类的执行需要config属性支持
    public MessageService() {
        LOGGER.debug("【构造方法】public MessageService() {}");
    }
    private boolean connect() { // 定义一个连接方法
        LOGGER.info("连接服务器:{}:{}", this.config.getHost(), this.config.getPort());
        return this.config.isEnable(); // 通过enable的状态来决定是否连接成功
    }
    public MessageSendStatus send(String msg) { // 消息发送
        if (this.connect()) {   // 消息发送之前需要首先连接服务器
            LOGGER.info("【消息发送】{}", msg); // 日志记录
            try {
                this.close(); // 关闭通道
            } catch (Exception e) {
                LOGGER.error("消息发送产生异常:{}", e.getMessage());
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        }
        LOGGER.error("无法创建消息发送通道,消息发送失败。");
        return MessageSendStatus.FAILURE; // 返回失败的状态
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理
    public void setConfig(MessageConfig config) { // 外部注入config实例
        LOGGER.debug("【设置MessageConfig依赖关联】public void setConfig(MessageConfig config) {}");
        this.config = config;
    }
    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


2、
package com.yootk.di.config;

public class MessageConfig { // 定义消息数据的配置类
    private String host;
    private int port;
    private boolean enable;
    public MessageConfig(String host, int port, boolean enable) {
        this.host = host;
        this.port = port;
        this.enable = enable;
    }
    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}


3、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    private MessageConfig config; // 这个类的执行需要config属性支持
    public MessageService(MessageConfig config) {
        LOGGER.debug("【构造方法】public MessageService() {}");
        this.config = config;
    }
    private boolean connect() { // 定义一个连接方法
        LOGGER.info("连接服务器:{}:{}", this.config.getHost(), this.config.getPort());
        return this.config.isEnable(); // 通过enable的状态来决定是否连接成功
    }
    public MessageSendStatus send(String msg) { // 消息发送
        if (this.connect()) {   // 消息发送之前需要首先连接服务器
            LOGGER.info("【消息发送】{}", msg); // 日志记录
            try {
                this.close(); // 关闭通道
            } catch (Exception e) {
                LOGGER.error("消息发送产生异常:{}", e.getMessage());
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        }
        LOGGER.error("无法创建消息发送通道,消息发送失败。");
        return MessageSendStatus.FAILURE; // 返回失败的状态
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理
    public void setConfig(MessageConfig config) { // 外部注入config实例
        LOGGER.debug("【设置MessageConfig依赖关联】public void setConfig(MessageConfig config) {}");
        this.config = config;
    }
    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


4、
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <constructor-arg value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <constructor-arg value="8869"/> <!-- 配置Bean属性 -->
        <constructor-arg value="1"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <constructor-arg ref="config"/> <!-- 引用关系的配置 -->
    </bean>

5、
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <constructor-arg index="2" value="1"/> <!-- 配置Bean属性 -->
        <constructor-arg index="1" value="8869"/> <!-- 配置Bean属性 -->
        <constructor-arg index="0" value="message.yootk.com"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <constructor-arg ref="config"/> <!-- 引用关系的配置 -->
    </bean>

通过参数名称配置构造方法数据

  • 虽然在 Spring 中可以利用“/”元素配置的参数顺序进行构造方法的内容设置,但是依然会有很多的开发者觉得这样的配置不够清晰,尤其是在参数内容较多时问题的排查就比较麻烦了。为了解决这样的设计需要,在 Spring 中提供可以通过构造参数的名称实现构造方法调用的处理,而这时的操作不仅需要在 XML 配置文件中定义,同时也需要在类的构造方法中使用"@ConstructorProperties”注解进行配置
6、
    @ConstructorProperties(value = {"paramHost", "paramPort", "paramEnable"})
    public MessageConfig(String host, int port, boolean enable) {
        this.host = host;
        this.port = port;
        this.enable = enable;
    }

7、
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <constructor-arg name="paramEnable" value="1"/> <!-- 配置Bean属性 -->
        <constructor-arg name="paramPort" value="8869"/> <!-- 配置Bean属性 -->
        <constructor-arg name="paramHost" value="message.yootk.com"/> <!-- 配置Bean属性 -->
    </bean>

自动装配

根据类型自动配置依赖关联

  • 依赖关联是 Spring 提供的重要技术支持,传统的做法是通过“/”元素中的“ref”属性实现结构关联,但是如果说此时项目中配置的 Bean 过多,就可以利用 Spring 所提供的自动装配的形式进行引用的处理
<bean id="config" class="w02.di.config.MessageConfig">
    <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
    <property name="port" value="8869"/> <!-- 配置Bean属性 -->
    <property name="enable" value="0"/> <!-- 配置Bean属性 -->
</bean>
<bean id="messageServiceDI" class="w02.di.service.MessageService" autowire="byType"/>

根据 Bean 定义的名称配置依赖关联

  • 由于 Spring 容器启动后所有的 Bean 对象全部都在 Spring 容器中保存,这样就有可能会出现一个类存在有多个 Bean 配置的场景出现,那么此时可以利用自动装配中的名称匹配的模式,自动将类属性名称与指定名称的 Bean-ID 进行关联,从而实现注入操作
<bean id="config" class="w02.di.config.MessageConfig">
    <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
    <property name="port" value="8869"/> <!-- 配置Bean属性 -->
    <property name="enable" value="0"/> <!-- 配置Bean属性 -->
</bean>
<bean id="definit" class="w02.di.config.MessageConfig">
    <property name="host" value="message.jixianit.com"/> <!-- 配置Bean属性 -->
    <property name="port" value="6969"/> <!-- 配置Bean属性 -->
    <property name="enable" value="on"/> <!-- 配置Bean属性 -->
</bean>
<bean id="messageServiceDI" class="w02.di.service.MessageService" autowire="byName"/>
1、
<bean id="config" class="com.yootk.di.config.MessageConfig">
    <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
    <property name="port" value="8869"/> <!-- 配置Bean属性 -->
    <property name="enable" value="0"/> <!-- 配置Bean属性 -->
</bean>
<bean id="messageService" class="com.yootk.di.service.MessageService" autowire="byType"/>


2、
   <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="8869"/> <!-- 配置Bean属性 -->
        <property name="enable" value="0"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.jixianit.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="6969"/> <!-- 配置Bean属性 -->
        <property name="enable" value="on"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService" autowire="byType"/>

3、
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="8869"/> <!-- 配置Bean属性 -->
        <property name="enable" value="0"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.jixianit.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="6969"/> <!-- 配置Bean属性 -->
        <property name="enable" value="on"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService" autowire="byName"/>

4、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    private MessageConfig messageConfig; // 这个类的执行需要config属性支持
    private boolean connect() { // 定义一个连接方法
        LOGGER.info("连接服务器:{}:{}", this.messageConfig.getHost(), this.messageConfig.getPort());
        return this.messageConfig.isEnable(); // 通过enable的状态来决定是否连接成功
    }
    public MessageSendStatus send(String msg) { // 消息发送
        if (this.connect()) {   // 消息发送之前需要首先连接服务器
            LOGGER.info("【消息发送】{}", msg); // 日志记录
            try {
                this.close(); // 关闭通道
            } catch (Exception e) {
                LOGGER.error("消息发送产生异常:{}", e.getMessage());
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        }
        LOGGER.error("无法创建消息发送通道,消息发送失败。");
        return MessageSendStatus.FAILURE; // 返回失败的状态
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理
    public void setMessageConfig(MessageConfig messageConfig) { // 外部注入config实例
        LOGGER.debug("【设置MessageConfig依赖关联】public void setMessageConfig(MessageConfig config) {}");
        this.messageConfig = messageConfig;
    }
    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


5、
    <bean id="config" class="com.yootk.di.config.MessageConfig" primary="true">
        <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="8869"/> <!-- 配置Bean属性 -->
        <property name="enable" value="0"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.jixianit.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="6969"/> <!-- 配置Bean属性 -->
        <property name="enable" value="on"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService" autowire="byType"/>

6、
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="message.yootk.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="8869"/> <!-- 配置Bean属性 -->
        <property name="enable" value="0"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig" autowire-candidate="false">
        <property name="host" value="message.jixianit.com"/> <!-- 配置Bean属性 -->
        <property name="port" value="6969"/> <!-- 配置Bean属性 -->
        <property name="enable" value="on"/> <!-- 配置Bean属性 -->
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService" autowire="byType"/>

prototype 原型设计模式

原始 Java 对象实例化管理

  • 在传统的 Java 语法的使用过程中,每一次都需要通过关键字 new 进行对象的实例化处理而后再为该对象配置属性内容,如果此时要产生很多个实例化对象,那么必然会造成严重的性能问题,

  • 在 Spring 之中由于需要通过配置文件定义所有的 Bean 实例,这样在进行 Bean 获取时都会存在有相应的数据,在默认情况下 Sprina 会基于单例(Sinaleton)的模式进行这些 Bean 的管理,这样不管外部对此 Bean 进行多少次的引用,最终也只会获取一个对象实例,这样的设计可以极大的节约堆内存空间的占用,并减少对象实例化所带来的重复性能开支。

Prototype 模式

  • 但是不同的用户在使用 Spring 框架的过程中会存在有不同的需求,例如,现在某些 Bean 对象不希望采用单例的模式进行管理,即:每次获取该对象时都要求存在有一个不同的 Bean 实例。这样一来就不能够使用默认的单例配置模式,同时为了尽可能的提升新对象的创建性能,就需要使用到原型(Prototype)设计模式,以一个已经完全初始化完成的 Bean 为原型进行对象的克隆处理
  • Spring 中在进行 Bean 配置时,可以通过 scope 属性进行模式的选择,默认的式为"singleton”,如果需要修改为原型模式则该选项定义为“prototype”即可
1、
package com.yootk.vo;

public class Dept {
    private Long deptno;
    private String dname;
    private String loc;

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    @Override
    public String toString() {
        return "【部门信息 - " + super.hashCode() + "】编号:" + this.deptno + "、名称:" + this.dname + "、位置:" + this.loc;
    }
}


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"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dept" class="com.yootk.vo.Dept"/>
</beans>

3、
package com.yootk.main;

import com.yootk.vo.Dept;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-base.xml");
        // 因为整个的Spring容器里面只存在有一个Dept类型的对象,所以可以直接根据类型获取
        Dept deptA = context.getBean(Dept.class);
        LOGGER.info("第一次获取Bean:{}", deptA);
        Dept deptB = context.getBean(Dept.class);
        LOGGER.info("第二次获取Bean:{}", deptB);
    }
}


4、
<?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.xsd">
    <!--<bean id="dept" class="com.yootk.vo.Dept" scope="singleton"/>-->
    <bean id="dept" class="com.yootk.vo.Dept" scope="prototype"/>
</beans>

5、
package com.yootk.vo;

public class Emp {
    private Long empno;
    private String ename;
    private Dept dept;

    public Long getEmpno() {
        return empno;
    }

    public void setEmpno(Long empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "【雇员信息 - "+super.toString()+"】编号:" + this.empno + "、姓名:" + this.ename;
    }
}


6、
<?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.xsd">
    <bean id="dept" class="com.yootk.vo.Dept" scope="prototype">
        <property name="deptno" value="10"/>
        <property name="dname" value="教学部"/>
        <property name="loc" value="北京"/>
    </bean>
    <bean id="emp" class="com.yootk.vo.Emp" scope="prototype">
        <property name="empno" value="7369"/>
        <property name="ename" value="爆可爱的小李"/>
        <property name="dept" ref="dept"/>
    </bean>
</beans>

7、
package com.yootk.main;

import com.yootk.vo.Dept;
import com.yootk.vo.Emp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-base.xml");
        // 因为整个的Spring容器里面只存在有一个Dept类型的对象,所以可以直接根据类型获取
        Emp empA = context.getBean(Emp.class);
        LOGGER.info("第一次获取Bean:{}", empA);
        LOGGER.info("第一次获取Bean:{}", empA.getDept());
        Emp empB = context.getBean(Emp.class);
        LOGGER.info("第二次获取Bean:{}", empB);
        LOGGER.info("第二次获取Bean:{}", empB.getDept());
    }
}

Bean 延迟初始化

延迟初始化

  • Spring 容器在启动时会对所有配置的 Bean 实例进行初始化管理,同时所有的初始化的 Bean 也都会保存在 Spring 容器中供开发者使用。如果此时项目中的 Bean 过多了,那么为了减少 Spring 容器初始化时的负担,可以选择在第一次使用时进行 Bean 的实例化处理,为此在“/”元素的配置中提供了“lazy-init”属性,如果该属性配置为 true,则表示启用延迟初始化管理。
1、
package com.yootk.vo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Dept {
    private static final Logger LOGGER = LoggerFactory.getLogger(Dept.class);
    private Long deptno;
    private String dname;
    private String loc;
    public Dept() {
        LOGGER.info("【构造方法】public Dept() {}");
    }

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        LOGGER.info("【Setter方法】public void setDeptno() {}");
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        LOGGER.info("【Setter方法】public void setDname() {}");
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        LOGGER.info("【Setter方法】public void setLoc() {}");
        this.loc = loc;
    }

    @Override
    public String toString() {
        return "【部门信息 - " + super.hashCode() + "】编号:" + this.deptno + "、名称:" + this.dname + "、位置:" + this.loc;
    }
}


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"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dept" class="com.yootk.vo.Dept">
        <property name="deptno" value="10"/>
        <property name="dname" value="教学部"/>
        <property name="loc" value="北京"/>
    </bean>
</beans>

3、
package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
    }
}


4、
<?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.xsd">
    <bean id="dept" class="com.yootk.vo.Dept" lazy-init="true">
        <property name="deptno" value="10"/>
        <property name="dname" value="教学部"/>
        <property name="loc" value="北京"/>
    </bean>
</beans>

5、
package com.yootk.main;

import com.yootk.vo.Dept;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        Dept dept = context.getBean(Dept.class); // 获取Bean对象
        LOGGER.info("{}", dept);
    }
}

注入数据集合

1、

package com.yootk.di.config;

public class MessageConfig { // 定义消息数据的配置类
    private String host;
    private int port;
    private boolean enable;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    @Override
    public String toString() {
        return "【MessageConfig - " + super.hashCode() + "】主机:" + this.host + "、端口:" + this.port + "、状态:" + this.enable;
    }
}


2、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.List;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    private List<MessageConfig> configs; // 这个类的执行需要config属性支持
    private MessageConfig currentConfig; // 当前使用的配置项

    private boolean connect() { // 定义一个连接方法
        LOGGER.info("连接服务器:{}:{}", this.currentConfig.getHost(), this.currentConfig.getPort());
        return this.currentConfig.isEnable(); // 通过enable的状态来决定是否连接成功
    }

    public MessageSendStatus send(String msg) { // 消息发送
        try {
            Iterator<MessageConfig> iterator = this.configs.iterator(); // 获取迭代对象
            while (iterator.hasNext()) {
                this.currentConfig = iterator.next(); // 【广播】向所有的通道进行消息发布
                if (this.connect()) {   // 消息发送之前需要首先连接服务器
                    LOGGER.info("【消息发送】{}", msg); // 日志记录
                    this.close(); // 关闭通道
                } else {
                    LOGGER.error("无法创建消息发送通道,消息发送失败。");
                }
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        } catch (Exception e) {
            LOGGER.error("消息发送产生异常:{}", e.getMessage());
            return MessageSendStatus.FAILURE; // 返回失败的状态
        }
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理

    public void setConfigs(List<MessageConfig> configs) { // Bean注入
        this.configs = configs;
    }

    public List<MessageConfig> getConfigs() { // 获取全部的配置项
        return configs;
    }

    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}



3、
<?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.xsd">
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.yootk.com"/>
        <property name="port" value="9090"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.jixianit.com"/>
        <property name="port" value="8989"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="configs">    <!--  集合配置  -->
            <list> <!--  形式一是进行引用,形式二是进行新的定义  -->
                <ref bean="config"/>
                <ref bean="definit"/>
                <!-- 此时的Bean是直接通过List进行管理,那么可以不设置名字 -->
                <bean class="com.yootk.di.config.MessageConfig">
                    <property name="host" value="edu.yootk.com"/>
                    <property name="port" value="8778"/>
                    <property name="enable" value="true"/>
                </bean>
            </list>
        </property>
    </bean>
</beans>

4、
package com.yootk.main;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        MessageService service = context.getBean(MessageService.class); // 根据类型获取Bean
        for (MessageConfig config : service.getConfigs()) { // 迭代集合输出
            LOGGER.info("MessageConfig配置项:{}", config);
        }
    }
}


6、
package com.yootk.main;

import com.yootk.di.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        MessageService service = context.getBean(MessageService.class); // 根据类型获取Bean
        service.send("沐言科技:www.yootk.com"); // 消息发送
    }
}


7、
package com.yootk.main;

import com.yootk.di.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        MessageService service = context.getBean(MessageService.class); // 根据类型获取Bean
        LOGGER.info("List实现子类:{}", service.getConfigs().getClass());
    }
}


8、
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="configs">    <!--  集合配置  -->
            <array> <!--  形式一是进行引用,形式二是进行新的定义  -->
                <ref bean="config"/>
                <ref bean="definit"/>
                <!-- 此时的Bean是直接通过List进行管理,那么可以不设置名字 -->
                <bean class="com.yootk.di.config.MessageConfig">
                    <property name="host" value="edu.yootk.com"/>
                    <property name="port" value="8778"/>
                    <property name="enable" value="true"/>
                </bean>
            </array>
        </property>
    </bean>

注入 SET 集合

1、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    private Set<MessageConfig> configs; // 这个类的执行需要config属性支持
    private MessageConfig currentConfig; // 当前使用的配置项

    private boolean connect() { // 定义一个连接方法
        LOGGER.info("连接服务器:{}:{}", this.currentConfig.getHost(), this.currentConfig.getPort());
        return this.currentConfig.isEnable(); // 通过enable的状态来决定是否连接成功
    }

    public MessageSendStatus send(String msg) { // 消息发送
        try {
            Iterator<MessageConfig> iterator = this.configs.iterator(); // 获取迭代对象
            while (iterator.hasNext()) {
                this.currentConfig = iterator.next(); // 【广播】向所有的通道进行消息发布
                if (this.connect()) {   // 消息发送之前需要首先连接服务器
                    LOGGER.info("【消息发送】{}", msg); // 日志记录
                    this.close(); // 关闭通道
                } else {
                    LOGGER.error("无法创建消息发送通道,消息发送失败。");
                }
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        } catch (Exception e) {
            LOGGER.error("消息发送产生异常:{}", e.getMessage());
            return MessageSendStatus.FAILURE; // 返回失败的状态
        }
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理

    public void setConfigs(Set<MessageConfig> configs) { // Bean注入
        this.configs = configs;
    }

    public Set<MessageConfig> getConfigs() { // 获取全部的配置项
        return configs;
    }

    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


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"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.yootk.com"/>
        <property name="port" value="9090"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.jixianit.com"/>
        <property name="port" value="8989"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="configs">    <!--  集合配置  -->
            <set> <!--  形式一是进行引用,形式二是进行新的定义  -->
                <ref bean="config"/>
                <ref bean="definit"/>
                <!-- 此时的Bean是直接通过List进行管理,那么可以不设置名字 -->
                <bean class="com.yootk.di.config.MessageConfig">
                    <property name="host" value="edu.yootk.com"/>
                    <property name="port" value="8778"/>
                    <property name="enable" value="true"/>
                </bean>
            </set>
        </property>
    </bean>
</beans>

3、
<?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.xsd">
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.yootk.com"/>
        <property name="port" value="9090"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.jixianit.com"/>
        <property name="port" value="8989"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="configs">    <!--  集合配置  -->
            <set> <!--  形式一是进行引用,形式二是进行新的定义  -->
                <ref bean="config"/>
                <bean class="com.yootk.di.config.MessageConfig">
                    <property name="host" value="www.yootk.com"/>
                    <property name="port" value="9090"/>
                    <property name="enable" value="true"/>
                </bean>
                <ref bean="definit"/>
                <bean class="com.yootk.di.config.MessageConfig">
                    <property name="host" value="www.jixianit.com"/>
                    <property name="port" value="8989"/>
                    <property name="enable" value="true"/>
                </bean>
                <!-- 此时的Bean是直接通过List进行管理,那么可以不设置名字 -->
                <bean class="com.yootk.di.config.MessageConfig">
                    <property name="host" value="edu.yootk.com"/>
                    <property name="port" value="8778"/>
                    <property name="enable" value="true"/>
                </bean>
            </set>
        </property>
    </bean>
</beans>

4、
package com.yootk.di.config;

import java.util.Objects;

public class MessageConfig { // 定义消息数据的配置类
    private String host;
    private int port;
    private boolean enable;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MessageConfig config = (MessageConfig) o;
        return port == config.port && enable == config.enable && host.equals(config.host);
    }

    @Override
    public int hashCode() {
        return Objects.hash(host, port, enable);
    }

    @Override
    public String toString() {
        return "【MessageConfig - " + super.hashCode() + "】主机:" + this.host + "、端口:" + this.port + "、状态:" + this.enable;
    }
}

注入 Map 集合

注入 Map 集合

-Java 类集之中可以依靠 Map 实现二元偶对象的集合存储,在 Spring 框架里面针对于此结构的存储也是可以基于配置文件的方式来实现注入管理的,在配置时需要基于"<map>"与“<entry/>”子元素实现定义

1、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    // 提醒:对于Map集合之中的KEY最好的方法就是使用String,如果要是自定义KEY,就需要HashCode()、equals()支持了
    private Map<String, MessageConfig> configs; // 这个类的执行需要config属性支持
    private MessageConfig currentConfig; // 当前使用的配置项
    private String currentKey; // 当前使用的KEY

    private boolean connect() { // 定义一个连接方法
        LOGGER.info("【{}】连接服务器:{}:{}", this.currentKey, this.currentConfig.getHost(), this.currentConfig.getPort());
        return this.currentConfig.isEnable(); // 通过enable的状态来决定是否连接成功
    }

    public MessageSendStatus send(String msg) { // 消息发送
        try {
            Iterator<Map.Entry<String, MessageConfig>> iterator =
                    this.configs.entrySet().iterator(); // 获取迭代对象
            while (iterator.hasNext()) {
                Map.Entry<String, MessageConfig> entry = iterator.next();
                this.currentKey = entry.getKey();
                this.currentConfig = entry.getValue(); // 【广播】向所有的通道进行消息发布
                if (this.connect()) {   // 消息发送之前需要首先连接服务器
                    LOGGER.info("【消息发送】{}", msg); // 日志记录
                    this.close(); // 关闭通道
                } else {
                    LOGGER.error("无法创建消息发送通道,消息发送失败。");
                }
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        } catch (Exception e) {
            LOGGER.error("消息发送产生异常:{}", e.getMessage());
            return MessageSendStatus.FAILURE; // 返回失败的状态
        }
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理


    public void setConfigs(Map<String, MessageConfig> configs) {
        this.configs = configs;
    }

    public Map<String, MessageConfig> getConfigs() {
        return configs;
    }

    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


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"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="config" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.yootk.com"/>
        <property name="port" value="9090"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="definit" class="com.yootk.di.config.MessageConfig">
        <property name="host" value="www.jixianit.com"/>
        <property name="port" value="8989"/>
        <property name="enable" value="true"/>
    </bean>
    <bean id="messageService" class="com.yootk.di.service.MessageService">
        <property name="configs">    <!--  集合配置  -->
            <map>
                <entry key="yootk" value-ref="config"/>
                <entry key="jixianit" value-ref="definit"/>
                <entry key="edu">
                    <bean class="com.yootk.di.config.MessageConfig">
                        <property name="host" value="edu.yootk.com"/>
                        <property name="port" value="8778"/>
                        <property name="enable" value="true"/>
                    </bean>
                </entry>
            </map>
        </property>
    </bean>
</beans>

3、
package com.yootk.main;

import com.yootk.di.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        MessageService service = context.getBean(MessageService.class); // 根据类型获取Bean
        service.send("沐言科技:www.yootk.com");
    }
}

注入 Properties 集合

注入 Properties 集合

  • java.util.Properties 是属性操作类,该类可以通过 I0 流实现属性的读写处理操作,由于所有的属性都是 String 型的数据,在一些项目的开发中可以通过该类实现配置项的定义 Spring 开发框架之中也支持有该类型的对象注入操作的支持,下面通过具体的步骤进行这一功能的实现
1、
package com.yootk.di.config;

import java.util.Properties;

public class MessageProperties { // 定义资源属性配置
    private String subject; // 操作主题
    // 一般的属性都是字符串的配置,例如,在后续使用到数据库的时候基本上都是字符串的资源
    private Properties attribute; // 定义属性

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public Properties getAttribute() {
        return attribute;
    }

    public void setAttribute(Properties attribute) {
        this.attribute = attribute;
    }
}


2、
    <bean id="messageProperties" class="com.yootk.di.config.MessageProperties">
        <property name="subject" value="沐言科技消息中心"/>
        <property name="attribute"> <!-- 进行属性的配置(KEY = VALUE) -->
            <props> <!-- 属性集合 -->
                <prop key="muyan">沐言科技:www.yootk.com</prop>
                <prop key="jixianit">视频列表:www.jixianit.com</prop>
                <prop key="edu">高薪就业编程训练营:edu.yootk.com</prop>
            </props>
        </property>
    </bean>

3、
package com.yootk.main;

import com.yootk.di.config.MessageProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        MessageProperties messageProperties = context.getBean(MessageProperties.class);
        LOGGER.info("【{}】属性配置:{}", messageProperties.getSubject(), messageProperties.getAttribute());
    }
}

Annotation 自动装配

Annotation 自动装配简介

基于 XML 实现的 Spring 配置

  • 在 Spring 早期的项目开发之中,所有的程序类都需要在 Spring 配置文件之中进行 Bean 注册后,才可以实现对象实例化以及依赖配置管理的操作。但是随着项目规模的逐步增这样的开发模式就会出现配置文件过大的问题,不仅对项目的开发带来不便,同时也为项目的维护带来极大的麻烦。

Spring 扫描配置

  • 为了解决这一设计问题,从 Spring 2.5 开发版本开始推出了基于注解方式的配置,该操作需要在类定义时追加 Spring 开发的注解。开发者只需要在 Spring 配置文件之中引入 context 命名空间,而后设置扫描包的路径后就可以直接实现指定包中所有类的自动注册,从而极大的简化开发者的配置难度,也减少了 Spring 配置文件的体积

Bean 相关注解

  • 在扫描配置的过程之中,最重要的是 org.springframework.stereotype 包中所四个核心注解,分别为:

    • Controller(控制层解)
    • Service(业务层注解)
    • Repositor (数据层注解)
    • Component(组件注解)
1、
<?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-3.3.xsd">
</beans>

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.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.3.xsd">
    <context:annotation-config/>     <!-- 启用Annotation配置注解支持 -->
    <context:component-scan base-package="com.yootk.service,com.yootk.dao,com.yootk.config"/>
</beans>

基于 Annotation 实现 Bean 注册

基于注解实现 Bean 注册与依赖配置

  • 为便于读者理解注解自动扫描配置的具体操作,下面将模拟一个基本的业务逻辑调用,在本次的操作中将分别创建数据层与业务层,随后数据层和业务层的实现子类分别使用"@Repository”和"@Service"注解进行定义,并结合“@Autowired”的注解实” 现依赖注入管理
1、

package com.yootk.vo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Dept {
    private static final Logger LOGGER = LoggerFactory.getLogger(Dept.class);
    private Long deptno;
    private String dname;
    private String loc;
    public Dept() {
        LOGGER.info("【构造方法】public Dept() {}");
    }

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        LOGGER.info("【Setter方法】public void setDeptno() {}");
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        LOGGER.info("【Setter方法】public void setDname() {}");
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        LOGGER.info("【Setter方法】public void setLoc() {}");
        this.loc = loc;
    }

    @Override
    public String toString() {
        return "【部门信息 - " + super.hashCode() + "】编号:" + this.deptno + "、名称:" + this.dname + "、位置:" + this.loc;
    }
}

2、
package com.yootk.dao;

import com.yootk.vo.Dept;

public interface IDeptDAO {
    public Dept findById(Long deptno); // 根据ID查询数据
}


3、
package com.yootk.dao.impl;

import com.yootk.dao.IDeptDAO;
import com.yootk.vo.Dept;
import org.springframework.stereotype.Repository;

@Repository // 数据层的注解
public class DeptDAOImpl implements IDeptDAO {
    @Override
    public Dept findById(Long deptno) { // 正常来讲,该操作通过数据库查询得到
        Dept dept = new Dept(); // 手工实现了
        dept.setDeptno(deptno); // 部门编号
        dept.setDname("沐言科技教学研发部"); // 属性配置
        dept.setLoc("北京");
        return dept;
    }
}


4、
package com.yootk.service;

import com.yootk.vo.Dept;

public interface IDeptService {
    public Dept get(Long deptno);
}

5、
package com.yootk.service.impl;

import com.yootk.dao.IDeptDAO;
import com.yootk.service.IDeptService;
import com.yootk.vo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service // 表示现在是业务层的实现类
public class DeptServiceImpl implements IDeptService {
    @Autowired // 实例的注入
    private IDeptDAO deptDAO; // 需要数据层的实例
    @Override
    public Dept get(Long deptno) {
        return this.deptDAO.findById(deptno);
    }
}


6、
package com.yootk.test;

import com.yootk.service.IDeptService;
import com.yootk.service.IMessageService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

// 表示要进行Spring配置文件的加载,后续也可能是进行配置类的加载
@ContextConfiguration(locations = {"classpath:spring/spring-base.xml"}) // 定义XML配置文件
@ExtendWith(SpringExtension.class) // 表示此时使用外部的测试工具(JUnit5)
public class TestDeptService {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(TestDeptService.class) ;// 获取日志实例
    @Autowired // 自动注入接口实例
    private IDeptService deptService; // 要使用的业务接口
    @Test
    public void testGet() {
        LOGGER.info("查询部门数据:{}", this.deptService.get(10L));
    }
}


7、
<?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">
    <context:annotation-config/>     <!-- 启用Annotation配置注解支持 -->
    <context:component-scan base-package="com.yootk.service,com.yootk.dao,com.yootk.config"/>
</beans>

Configuration 注解

手工注册 Bean 实例

  • 虽然自动扫描注册可以减少了 Bean 配置文件的定义,但是在实际的项目开发过程中依然会存在有一些属性配置的需要,例如,在之前所讲解的 MessageService 与 MessageConfig 结构中,开发者就需要在 MessageConfig 定义时提供有多个属性的配置,而这时就可以考虑通过“@Configuration"与“@Bean”的注解来实现,同时通过该配置定义的 Bean 也可以依据配置方法的参数实现自动依赖的引用
1、
package com.yootk.di.config;

import java.util.Objects;

public class MessageConfig { // 定义消息数据的配置类
    private String host;
    private int port;
    private boolean enable;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MessageConfig config = (MessageConfig) o;
        return port == config.port && enable == config.enable && host.equals(config.host);
    }

    @Override
    public int hashCode() {
        return Objects.hash(host, port, enable);
    }

    @Override
    public String toString() {
        return "【MessageConfig - " + super.hashCode() + "】主机:" + this.host + "、端口:" + this.port + "、状态:" + this.enable;
    }
}


2、
package com.yootk.di.service;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.type.MessageSendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MessageService implements AutoCloseable { // 消息的服务处理
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageService.class);
    // 提醒:对于Map集合之中的KEY最好的方法就是使用String,如果要是自定义KEY,就需要HashCode()、equals()支持了
    private Map<String, MessageConfig> configs; // 这个类的执行需要config属性支持
    private MessageConfig currentConfig; // 当前使用的配置项
    private String currentKey; // 当前使用的KEY

    private boolean connect() { // 定义一个连接方法
        LOGGER.info("【{}】连接服务器:{}:{}", this.currentKey, this.currentConfig.getHost(), this.currentConfig.getPort());
        return this.currentConfig.isEnable(); // 通过enable的状态来决定是否连接成功
    }

    public MessageSendStatus send(String msg) { // 消息发送
        try {
            Iterator<Map.Entry<String, MessageConfig>> iterator =
                    this.configs.entrySet().iterator(); // 获取迭代对象
            while (iterator.hasNext()) {
                Map.Entry<String, MessageConfig> entry = iterator.next();
                this.currentKey = entry.getKey();
                this.currentConfig = entry.getValue(); // 【广播】向所有的通道进行消息发布
                if (this.connect()) {   // 消息发送之前需要首先连接服务器
                    LOGGER.info("【消息发送】{}", msg); // 日志记录
                    this.close(); // 关闭通道
                } else {
                    LOGGER.error("无法创建消息发送通道,消息发送失败。");
                }
            }
            return MessageSendStatus.SUCCESS; // 返回成功的状态
        } catch (Exception e) {
            LOGGER.error("消息发送产生异常:{}", e.getMessage());
            return MessageSendStatus.FAILURE; // 返回失败的状态
        }
    }
    // 此时该Bean(注册完成的类对象),之中的config属性需要通过配置文件定义注入管理


    public void setConfigs(Map<String, MessageConfig> configs) {
        this.configs = configs;
    }

    public Map<String, MessageConfig> getConfigs() {
        return configs;
    }

    @Override
    public void close() throws Exception {
        LOGGER.info("消息发送完毕,断开消息发送通道.");
    }
}


3、

package com.yootk.config;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.service.MessageService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration // 该注解也表示进行Bean注册
public class YootkConfig { // 定义配置类
    // 如果此时定义的Bean没有编写任何的名称,则使用方法名称作为Bean名称
    @Bean
    public MessageConfig config() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("www.yootk.com"); // 手工属性配置
        config.setPort(9090); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Bean("definit") // 自己编写一个Bean名称,不要系统自动设置了
    public MessageConfig getMessage() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("www.jixianit.com"); // 手工属性配置
        config.setPort(8989); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Bean("edu") // 自己编写一个Bean名称,不要系统自动设置了
    public MessageConfig edu() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("edu.yootk.com"); // 手工属性配置
        config.setPort(7979); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Bean("messageService") // 大部分的情况下都不需要编写名称
    public MessageService messageService(
            MessageConfig config,
            MessageConfig definit,
            MessageConfig edu) {
        Map<String, MessageConfig> map = new HashMap<>();
        map.put("yootk", config);
        map.put("jixianit", definit);
        map.put("edu", edu);
        MessageService service = new MessageService();
        service.setConfigs(map); // 属性设置
        return service;
    }
    @Bean // 大部分的情况下都不需要编写名称
    public MessageService messageService(
            @Qualifier("config") MessageConfig config,
            @Qualifier("definit") MessageConfig definit,
            @Qualifier("edu") MessageConfig edu) {
        Map<String, MessageConfig> map = new HashMap<>();
        map.put("yootk", config);
        map.put("jixianit", definit);
        map.put("edu", edu);
        MessageService service = new MessageService();
        service.setConfigs(map); // 属性设置
        return service;
    }
}

4、
package com.yootk.main;

import com.yootk.di.config.MessageProperties;
import com.yootk.di.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
        MessageService messageService = context.getBean(MessageService.class);
        messageService.send("沐言科技:www.yootk.com");
    }
}

Qualifier 注解

依赖注入

  • 在 Spring 容器之中管理的类可以依靠“@Autowired”注解进行注入操作,而该注解在进行注入时首先会根据属性的名称而当名称(byName)进行所依赖 Bean 的匹配,不匹配时将根据属性的类型(byType)进行 Bean 匹配
1、
package com.yootk.config;

import com.yootk.di.config.MessageConfig;
import com.yootk.di.service.MessageService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration // 该注解也表示进行Bean注册
public class YootkConfig { // 定义配置类
    // 如果此时定义的Bean没有编写任何的名称,则使用方法名称作为Bean名称
    @Bean
    public MessageConfig config() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("www.yootk.com"); // 手工属性配置
        config.setPort(9090); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Bean("definit") // 自己编写一个Bean名称,不要系统自动设置了
    public MessageConfig getMessage() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("www.jixianit.com"); // 手工属性配置
        config.setPort(8989); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Bean("edu") // 自己编写一个Bean名称,不要系统自动设置了
    public MessageConfig edu() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("edu.yootk.com"); // 手工属性配置
        config.setPort(7979); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Bean // 大部分的情况下都不需要编写名称
    public MessageService messageServiceMain(
            MessageConfig config,
            MessageConfig definit,
            MessageConfig edu) {
        Map<String, MessageConfig> map = new HashMap<>();
        map.put("yootk", config);
        map.put("jixianit", definit);
        map.put("edu", edu);
        MessageService service = new MessageService();
        service.setConfigs(map); // 属性设置
        return service;
    }
    @Bean // 大部分的情况下都不需要编写名称
    public MessageService messageServiceBack(
            MessageConfig config,
            MessageConfig definit,
            MessageConfig edu) {
        Map<String, MessageConfig> map = new HashMap<>();
        map.put("yootk", config);
        map.put("jixianit", definit);
        map.put("edu", edu);
        MessageService service = new MessageService();
        service.setConfigs(map); // 属性设置
        return service;
    }
}

2、
package com.yootk.test;

import com.yootk.di.service.MessageService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

// 表示要进行Spring配置文件的加载,后续也可能是进行配置类的加载
@ContextConfiguration(locations = {"classpath:spring/spring-base.xml"}) // 定义XML配置文件
@ExtendWith(SpringExtension.class) // 表示此时使用外部的测试工具(JUnit5)
public class TestMessageServiceTwo {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(TestMessageServiceTwo.class) ;// 获取日志实例
    @Autowired // 自动注入接口实例
    private MessageService messageServiceMain; // 要使用的业务接口
    @Test
    public void testSend() {
        this.messageServiceMain.send("沐言科技:www.yootk.com"); // 调用业务方法
    }
}


3、
package com.yootk.test;

import com.yootk.di.service.MessageService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

// 表示要进行Spring配置文件的加载,后续也可能是进行配置类的加载
@ContextConfiguration(locations = {"classpath:spring/spring-base.xml"}) // 定义XML配置文件
@ExtendWith(SpringExtension.class) // 表示此时使用外部的测试工具(JUnit5)
public class TestMessageServiceTwo {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(TestMessageServiceTwo.class) ;// 获取日志实例
    @Autowired // 自动注入接口实例
    private MessageService messageServiceBO; // 要使用的业务接口
    @Test
    public void testSend() {
        this.messageServiceBO.send("沐言科技:www.yootk.com"); // 调用业务方法
    }
}

@Primary

  • 在 Spring 中如果此时注入的 Bean 对象提供多个,那么可以在优先使用的 Bean 操作方法中利用"@Primary"注解配置优先选择。

DependsOn 注解

DependsOn 注解

  • 在默认情况下一个配置类中所定义“@Bean”注册操作都是根据代码的定义顺序执行的,但是如果说此时一个配置类中的 Bean 配置过多,并且会由不同的使用者修改,那么就有可能会导致 Bean 实例化顺序产生改变,从而影响到程序的正确执行。在 Spring 中为了解决此类问题,提供了“@DependsOn”注解,该注解表示当前的 Bean 配置必须在指定 Bean 配置完成后再处理。
1、
package com.yootk.config;

import com.yootk.vo.Dept;
import com.yootk.vo.Emp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 该注解也表示进行Bean注册
public class MuYanConfig { // 定义配置类
    private static final Logger LOGGER = LoggerFactory.getLogger(MuYanConfig.class);
    @Bean
    public Emp emp() {
        LOGGER.info("【Emp】雇员Bean实例化。");
        Emp emp = new Emp();
        return emp;
    }
    @Bean
    public Dept dept() {
        LOGGER.info("【Dept】部门Bean实例化。");
        Dept dept = new Dept();
        return dept;
    }
}


2、
package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER = LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) {
        // 容器的启动需要使用到特定的接口和类,此时的配置文件保存在CLASSPATH路径下,所以直接使用此类实例化
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring/spring-base.xml");
    }
}


3、
package com.yootk.config;

import com.yootk.vo.Dept;
import com.yootk.vo.Emp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

@Configuration // 该注解也表示进行Bean注册
public class MuYanConfig { // 定义配置类
    private static final Logger LOGGER = LoggerFactory.getLogger(MuYanConfig.class);
    @Bean
    @DependsOn("dept") // 该操作需要等待dept的Bean注册完成
    public Emp emp() {
        LOGGER.info("【Emp】雇员Bean实例化。");
        Emp emp = new Emp();
        return emp;
    }
    @Bean
    public Dept dept() {
        LOGGER.info("【Dept】部门Bean实例化。");
        Dept dept = new Dept();
        return dept;
    }
}

Conditional 注解

Condition 条件判断

  • 在 Spring 中所有在配置类中定义的注册 Bean 方法,都会自动的注册到 Spring 容器之中如果说现在某些 Bean 在满足一定的条件后才可以注册,这个时候就要通过 Condition 接口来定义条件处理逻辑
1、
package com.yootk.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class BookCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false; // 表示不启用
    }
}


2、
package com.yootk.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class EduCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 正常的配置下是应该存在有某些处理逻辑在内的
        return true; // 表示启用
    }
}


3、
package com.yootk.config;

import com.yootk.condition.BookCondition;
import com.yootk.condition.EduCondition;
import com.yootk.di.config.MessageConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration // 该注解也表示进行Bean注册
public class YootkConfig { // 定义配置类
    @Conditional({BookCondition.class}) // 定义处理条件
    @Bean
    public MessageConfig book() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("www.yootk.com"); // 手工属性配置
        config.setPort(9090); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
    @Conditional({EduCondition.class}) // 定义处理条件
    @Bean("edu") // 自己编写一个Bean名称,不要系统自动设置了
    public MessageConfig edu() {
        MessageConfig config = new MessageConfig(); // 手工实例化Bean对象
        // 现在为止所有的属性都是通过方法配置的,那么有可能该属性是通过其他的途径得到的数据内容
        config.setHost("edu.yootk.com"); // 手工属性配置
        config.setPort(7979); // 手工属性配置
        config.setEnable(true); // 手工属性配置
        return config;
    }
}


4、
package com.yootk.test;

import com.yootk.di.config.MessageConfig;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

// 表示要进行Spring配置文件的加载,后续也可能是进行配置类的加载
@ContextConfiguration(locations = {"classpath:spring/spring-base.xml"}) // 定义XML配置文件
@ExtendWith(SpringExtension.class) // 表示此时使用外部的测试工具(JUnit5)
public class TestMessageConfig {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(TestMessageConfig.class) ;// 获取日志实例
    @Autowired
    private MessageConfig config; // 要使用的业务接口
    @Test
    public void testConfig() {
        LOGGER.info("{}", this.config);
    }
}

Profile 注解

Profie 多环境处理

  • 一个完整的项目除了要进行代码的编写之外,还需要经过测试,才能够进行生产环境的部署。所以一个项目有可能会处于不同的项目应用环境,在 Spring 中为了便于这种应用环境的管理,提供了 Profile 配置支持。这样开发者就可以在不同的应用环境下进行不同 Profile 的配置,从而保证项目的正确运行
1、
package com.yootk.config.dev;

import com.yootk.di.config.MessageConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev") // 当前为dev开发环境
public class YootkMessageConfig {
    @Bean("messageConfig") // Bean的名称自定义,不再使用方法名称
    public MessageConfig devMessageConfig() {
        MessageConfig config = new MessageConfig();
        config.setHost("dev.message.yootk.com");
        config.setEnable(true);
        config.setPort(8869);
        return config;
    }
}


2、
package com.yootk.config.test;

import com.yootk.di.config.MessageConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("test") // 当前为dev开发环境
public class YootkMessageConfig {
    @Bean("messageConfig") // Bean的名称自定义,不再使用方法名称
    public MessageConfig devMessageConfig() {
        MessageConfig config = new MessageConfig();
        config.setHost("test.message.yootk.com");
        config.setEnable(true);
        config.setPort(8896);
        return config;
    }
}


3、
package com.yootk.config.product;

import com.yootk.di.config.MessageConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("product") // 当前为dev开发环境
public class YootkMessageConfig {
    @Bean("messageConfig") // Bean的名称自定义,不再使用方法名称
    public MessageConfig devMessageConfig() {
        MessageConfig config = new MessageConfig();
        config.setHost("product.message.yootk.com");
        config.setEnable(true);
        config.setPort(8896);
        return config;
    }
}


4、
package com.yootk.test;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.Arrays;

// 表示要进行Spring配置文件的加载,后续也可能是进行配置类的加载
@ContextConfiguration(locations = {"classpath:spring/spring-base.xml"}) // 定义XML配置文件
@ExtendWith(SpringExtension.class) // 表示此时使用外部的测试工具(JUnit5)
@ActiveProfiles("product") // 设置profile信息
public class TestSpringProfile {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(TestSpringProfile.class) ;// 获取日志实例
    @Autowired
    private ApplicationContext context; // 要使用的业务接口
    @Test
    public void testConfig() {
        LOGGER.info("{}", Arrays.toString(this.context.getEnvironment().getActiveProfiles()));
    }
}

ComponentScan 注解

包扫描注解

  • 在直接使用 Spring 开发框架进行项目开发过程中,大部分都是直接在 XML 配置文件中进行的 Spring 扫描包配置的,但是考虑到“零配置”的设计需要,在 Spring 内部又提供了"@ComponentScan'包扫描的注解定义,利用该注解也可以实现扫描包配置
1、
<?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">
    <context:annotation-config/>     <!-- 启用Annotation配置注解支持 -->
    <context:component-scan base-package="com.yootk.config"/>
</beans>

2、
package com.yootk.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.yootk.service", "com.yootk.dao"}) // 定义扫描包
public class GlobalConfig { // 全局配置类
}


3、
package com.yootk.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScans({@ComponentScan({"com.yootk.service"}),
        @ComponentScan({"com.yootk.dao"})})
public class GlobalConfig { // 全局配置类
}

demo


上次编辑于: