查看: 99|回复: 1

Spring IoC学习笔记

[复制链接]

1

主题

6

帖子

3

积分

新手上路

Rank: 1

积分
3
发表于 2022-9-23 10:34:36 | 显示全部楼层 |阅读模式
Spring IoC -- 控制反转


  • IOC控制反转,是一种设计理念
  • 由代理人来创建与管理对象,消费者通过代理人来获取对象
  • IOC的目的是降低对象之间直接耦合
  • 加入IOC容器将对象统一管理,让对象关系变为弱耦合
  • 用于统一创建与管理对象依赖
DI依赖注入


  • IOC是设计理念,是现代程序设计遵循的标准,是宏观目标
  • DI是具体技术实现,是微观实现
  • DI在Java中利用反射技术实现对象注入
狭义的Spring框架


  • Spring框架是企业开发复杂性的一站式解决方案
  • Spring框架的核心是IOC容器与AOP面向切面编程
  • Spring IOC负责创建与管理系统对象,并在此基础上扩展功能
Spring IoC容器职责


  • 对象的控制权交由第三方统一管理(IoC控制反转)
  • 利用Java反射技术实现运行时对象创建与关联(DI依赖注入)
  • 基于配置提高应用程序的可维护性与扩展性
Spring IoC初体验

1.加入依赖
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.12.RELEASE</version>
</dependency>2.在resource 下新建applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--bean标签-用于实例化Java对象的标签-->
    <!--在IoC容器启动时,自动由Spring实例化Apple对象,取名sweetApple放入到容器中-->
    <bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
        <!--设置对象对应的属性-->
        <property name="title" value="红富士"></property>
        <property name="origin" value="欧洲"></property>
        <property name="color" value="红色"></property>
    </bean>

    <bean id="sourApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="青苹果"></property>
        <property name="origin" value="中亚"></property>
        <property name="color" value="绿色"></property>
    </bean>

    <bean id="softApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="金帅"></property>
        <property name="origin" value="中国"></property>
        <property name="color" value="黄色"></property>
    </bean>
   
    <bean id="lily" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="莉莉"/>
        <property name="apple" ref="sweetApple"/>
    </bean>

    <bean id="andy" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="安迪"/>
        <property name="apple" ref="sourApple"/>
    </bean>

    <bean id="luna" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="露娜"/>
        <property name="apple" ref="softApple"/>
    </bean>

</beans>3.创建Spring Application类
package com.imooc.spring.ioc;

import com.imooc.spring.ioc.entity.Apple;
import com.imooc.spring.ioc.entity.Child;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author R.Yu
*/
public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        // 从IoC容器中提取beanId=sweetApple的对象
        Apple sweetApple = context.getBean("sweetApple", Apple.class);
        System.out.println(sweetApple.getTitle());
        Child lily = context.getBean("lily", Child.class);
        Child andy = context.getBean("andy", Child.class);
        Child luna = context.getBean("luna", Child.class);
        lily.eat();
        andy.eat();
        luna.eat();
    }
}XML管理对象(Bean)

1.基于XML配置Bean

实例化Bean的三种方式


  • 基于构造方法对象实例化
  • 基于静态工厂实例化
  • 基于工厂实例方法实例化
1.基于构造方法对象实例化
1.利用构造方法参数名实例化

<bean id="apple" class="com.imooc.spring.ioc.entity.Apple">
    <constructor-arg name="title" value="红富士"/>
    <constructor-arg name="color" value="红色"/>
    <constructor-arg name="origin" value="欧洲"/>
</bean>2.利用构造方法参数位置实例化<不推荐>

<bean id="apple3" class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg index="0" value="红富士"/>
        <constructor-arg index="1" value="红色"/>
        <constructor-arg index="2" value="欧洲"/>
</bean>2.基于静态工厂实例化

1.创建工厂
package com.imooc.spring.ioc.factory;

import com.imooc.spring.ioc.entity.Apple;

/**
* 静态工厂通过静态方法创建对象,隐藏创建对象的细节
* @author R.Yu
*/
public class AppleStaticFactory {
    public static Apple createSweetApple() {
        Apple apple = new Apple();
        apple.setTitle("红富士");
        apple.setOrigin("欧洲");
        apple.setColor("红色");
        return apple;
    }
}2.配置xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--利用静态工厂获取对象-->
    <bean id="apple4" class="com.imooc.spring.ioc.factory.AppleStaticFactory"
          factory-method="createSweetApple"/>
</beans>3.基于工厂实例方法实例化

1.创建工厂实例方法类
package com.imooc.spring.ioc.factory;

import com.imooc.spring.ioc.entity.Apple;

/**
* 工厂实例方法创建对象是指IoC容器对工厂类进行实例化并调用对应的实例方法创建对象的过程
* @author R.Yu
*/
public class AppleFactoryInstance {
    public Apple createSweetApple() {
        Apple apple = new Apple();
        apple.setTitle("红富士");
        apple.setOrigin("欧洲");
        apple.setColor("红色");
        return apple;
    }
}2.配置xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
   
    <!--利用工厂实例方法获取对象-->
    <bean id="factoryInstance" class="com.imooc.spring.ioc.factory.AppleFactoryInstance"/>
    <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>
</beans>从IoC容器中获取Bean

id与name属性相同点


  • bean id与name都是设置对象在IoC容器中唯一标识
  • 两者在同一个配置文件中都不允许出现重复
  • 两者允许在多个配置文件中出现重复,新对象覆盖旧对象(新旧对象取决于配置文件的加载顺序)
id与name属性区别


  • id要求更为严格,一次只能定义一个对象标识(推荐)
  • name更为宽松,一次允许定义多个对象标识,用逗号隔开
  • tips:id与name的命名要求有意义,按驼峰命名书写
没有id与name的bean默认使用类名全称作为bean标识
<bean  class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg name="title" value="红富士"/>
        <constructor-arg name="color" value="红色"/>
        <constructor-arg name="origin" value="欧洲"/>
</bean>
Apple apple = context.getBean("com.imooc.spring.ioc.entity.Apple",Apple.class);路径表达式用法


  • 加载单个配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml")

  • 加载多配置文件
String[] configLocations = new String[]{"classpath:applicationContext.xml","classpath:applicationContext-1.xml"};
ApplicationContext context = new ClassPathXmlApplication(configLocations);路径表达式
表达式实例说明
classpath:config.xml扫描classpath根路径(不包含jar)的config.xml
classpath:com/imooc/config.xml扫描classpath下(不包含jar)com.imooc包中的config.xml
classpath*:com/imooc/config.xml扫描classpath下(包含jar)com.imooc包中的config.xml
classpath:config-*.xml扫描classpath根路径下所有以config-开头的xml文件
classpath:com/**/config.xml扫描com包下(包含任何子包)的config.xml
file:c:/config.xml扫描C盘根路径config.xml
对象依赖注入


  • 依赖注入是指运行时将容器内对象利用反射赋给其他对象的操作
  • 基于setter方法注入对象(bean property)
  • 基于构造方法注入对象(bean constructor-arg)
注入集合对象

准备java实体类
package com.imooc.spring.ioc.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

/**
* @author R.Yu
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Company {
    private Set<String> rooms;
    private Map<String,Computer> computers;
    private Properties info;
}
package com.imooc.spring.ioc.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author R.Yu
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Computer {
    private String brand;
    private String type;
    private String sn;
    private Float price;
}

  • 注入List/Set/Map/Property
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
   
    <bean id="c1" class="com.imooc.spring.ioc.entity.Computer">
        <constructor-arg name="brand" value="联想"/>
        <constructor-arg name="type" value="台式机"/>
        <constructor-arg name="sn" value="1234232"/>
        <constructor-arg name="price" value="5929"/>
    </bean>

    <bean id="company" class="com.imooc.spring.ioc.entity.Company">
        <property name="rooms">
            <set>
                <value>2001-总裁办</value>
                <value>2003-总经理办公室</value>
                <value>2010-研发部会议室</value>
                <value>2010-研发部会议室</value>
            </set>
        </property>
        <property name="computers">
            <map>
                <entry key="dev-88172" value-ref="c1"/>
                <!--也可以这样写-->
                <entry key="dev-88173">
                    <bean class="com.imooc.spring.ioc.entity.Computer">
                        <constructor-arg name="brand" value="联想"/>
                        <constructor-arg name="type" value="笔记本"/>
                        <constructor-arg name="sn" value="234234232"/>
                        <constructor-arg name="price" value="7989"/>
                    </bean>
                </entry>
            </map>
        </property>
        <property name="info">
            <props>
                <prop key="phone">010-2343123</prop>
                <prop key="address">北京市朝阳区XXX路XX号</prop>
                <prop key="website">http://www.xxx.com</prop>
            </props>
        </property>
    </bean>
</beans>
public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Company company = context.getBean("company", Company.class);
        System.out.println(company);
        String phone = company.getInfo().getProperty("phone");
        System.out.println("phone = " + phone);

    }
}查看容器类对象

public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        // 获取容器内所有beanId数组
        String[] beanNames = context.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            System.out.println(beanName);
            System.out.println("类型:" + context.getBean(beanName).getClass().getName());
            System.out.println("内容:" + context.getBean(beanName));
        }
    }
}bean scope属性


  • bean scope属性用于决定对象何时被创建与作用范围
  • bean scope配置将影响容器内对象的数量
  • 默认情况下bean会在IoC容器创建后自动实例化,全局唯一
属性清单
scope属性说明
singleton单例(默认值),每一个容器有且只有唯一的实例,实例被全局共享
prototype多例,每次使用时都是创建一个实例
requestweb环境下,每一次独立请求存在唯一实例
sessionweb环境下,每一个session存在有唯一实例
global sessionportlet的web应用的共享session中
websocket每一次WebSocket连接中存在唯一实例
singleton在容器是单例多线程执行,存在线程安全风险
prototype在容器中多实例,占用更多 资源,不存在线程安全问题
<bean id="..." class="..." scope="prototype">...</bean>singleton与prototype对比
singletonprototype
对象数量全局唯一存在多个
实例化时机IoC容器启动时getBean()或对象注入时
线程安全问题存在不存在
执行效率
bean的生命周期


  • IoC容器准备初始化解析XML (容器行为)
  • 对象实例化执行构造方法(对象行为)
  • IoC容器为对象注入属性(容器行为)
  • 调用init-method初始化方法(对象行为)
  • IoC容器初始化完毕(容器行为)
  • 执行业务代码(对象行为)
  • IoC容器准备销毁(容器行为)
  • 调用destroy-method释放资源(对象行为)
  • IoC容器销毁完毕(容器行为)
创建Java类
package com.imooc.spring.ioc.entity;

public class Order {
    private Float price;
    private Integer quantity;
    private Float total;

    public Order(){
        System.out.println("创建Order对象," + this);
    }

    public void init(){
        System.out.println("执行init()方法");
        total = price * quantity;
    }
    public void pay(){
        System.out.println("订单金额为:" + total);
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        System.out.println("设置price:" + price);
        this.price = price;
    }

    public Integer getQuantity() {
        return quantity;
    }

    public void setQuantity(Integer quantity) {
        System.out.println("设置quantity:" + quantity);
        this.quantity = quantity;
    }

    public Float getTotal() {
        return total;
    }

    public void setTotal(Float total) {
        this.total = total;
    }

    public void destroy(){
        System.out.println("释放与订单对象相关的资源");
    }
}配置Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="order1" class="com.imooc.spring.ioc.entity.Order" init-method="init" destroy-method="destroy">
        <property name="price" value="19.8"/>
        <property name="quantity" value="1000"/>
    </bean>
</beans>
测试
package com.imooc.spring.ioc;

import com.imooc.spring.ioc.dao.UserDao;
import com.imooc.spring.ioc.entity.Order;
import com.imooc.spring.ioc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringApplication {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        System.out.println("======IoC容器已初始化=======");

        Order order1 = context.getBean("order1", Order.class);
        order1.pay();

        context.registerShutdownHook();
    }
}
​运行结果如下:
创建Order对象,com.imooc.spring.ioc.entity.Order@52af6cff
设置price:19.8
设置quantity:1000
执行init()方法
======IoC容器已初始化=======
订单金额为:19800.0
释放与订单对象相关的资源实现极简IoC容器
引入依赖
<!--Dom4j是Java的XML解析组件  -->
<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <versino>2.1.1</versino>
</dependency>
<!-- Jaxen是Xpath表达式解释器 -->
<dependency>
    <groupId>jaxen</groupId>
    <artifactId>jaxen</artifactId>
    <versino>1.1.1</versino>
</dependency>创建容器接口
public interface ApplicationContext {
    public Object getBean(Stirng beanId);
}创建对象
public class ClassPathXmlApplication implements ApplicationContext {
    private Map iocContainer = new HashMap();
    public ClassPathXmlApplication() {
        try {
            String filePath = this.getClass().getResource("/applicationContext.xml").getPath();
            filePath = new URLDecoder().decode(filePath, "UTF-8");
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(filePath));
            List<Node> beans = document.getRootElement().selectNodes("bean");
            for(Node node : beans) {
                Element ele = (Element)node;
                String id = ele.attributeValue("id");
                String className = ele.attributeValue("class");
                Class c = Class.forName(className);
                Object obj = c.newInstance();
                List<Node> properties = ele.selectNodes("property");
                for(Node p : properties) {
                    Element property = (Element) p;
                    String propName = property.attributeValue("name");
                    String propValue = property.attributeValue("value");
                    String setMethodName = "set" + propName.substring(0,1).toUpperCase() + propName.substring(1);
                    Method setMethod = c.getMethod(setMethodName, String.class);
                    setMethod.invoke(obj, propValue); // 通过setter方法注入数据
                }
                iocContainer.put(id, obj);
            }
            System.out.println("IoC容器初始化完毕");
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    public Objext getBean(String beanId) {
        return iocContainer.get(beanId);
    }
}
2.基于注解配置Bean

四种组件类型注解

注解说明
@Component组件注解,通用注解,被该注解描述的类将被IoC容器管理并实例化
@Controller语义注解,说明当前类是MVC应用中的控制器类
@Service语义注解,说明当前类是Service业务服务类
@Repository语义注解,说明当前类用于业务持久层,通常描述对应Dao类
开启组件扫描
<!--XML配置开启组件扫描,才能使用注解-->
<context:component-scan base-package="com.imooc">
    <context:exclude-filter type="regex" expression="com.imooc.exl.*"/>
</context:component-scan>创建applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--在IoC容器初始化时自动扫描四种组件类型注解并完成实例化
        @Repository  @Service  @Controller  @Component
    -->
    <!--context为命名空间-->
    <context:component-scan base-package="com.imooc"/>
</beans>
package com.imooc.spring.ioc.dao;

import org.springframework.stereotype.Repository;

// 组件类型注解默认beanId为类名首字母小写  userDao   也可以进行手动设置value属性
@Repository("udao")
public class UserDao {
}两类自动装配注解

分类注解说明
按类型装配@Autowired按容器内对象类型动态注入属性,由Spring机构提供
@Inject基于JSR-330标准,其他同@Autowired,但不支持required属性
按名称装配@Named与@Inject配合使用,JSR-330规范,按属性名自动装配属性
@Resource基于JSR-250规范,优先按名称、再按类型智能匹配
package com.imooc.spring.ioc.service;

import com.imooc.spring.ioc.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    // Spring IoC容器会自动通过反射技术将属性private修饰符自动改为public,直接进行赋值,不再执行set方法
    @Autowired
    private UserDao udao;

    public UserService() {
        System.out.println("正在创建UserService:" + this);

    }

    public UserDao getUdao() {
        return udao;
    }

    public void setUdao(UserDao udao) {
        System.out.println("setUdao = " + udao);
        this.udao = udao;
    }
}
public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService.getUdao());
    }
}结果如下:
正在创建UserDao:com.imooc.spring.ioc.dao.UserDao@544a2ea6
正在创建UserService:com.imooc.spring.ioc.service.UserService@47db50c5
com.imooc.spring.ioc.dao.UserDao@544a2ea6

package com.imooc.spring.ioc.service;

import com.imooc.spring.ioc.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* @author R.Yu
*/
@Service
public class UserService {
    // @Autowired
    // Spring IoC容器会自动通过反射技术将属性private修饰符自动改为public,直接进行赋值,不再执行set方法
    private UserDao udao;

    public UserService() {
        System.out.println("正在创建UserService:" + this);

    }

    public UserDao getUdao() {
        return udao;
    }

    @Autowired
    // 如果装配注解放在set方法上,则自动按类型/名称对set方法参数进行注入
    public void setUdao(UserDao udao) {
        System.out.println("setUdao = " + udao);
        this.udao = udao;
    }
}结果如下:
正在创建UserDao:com.imooc.spring.ioc.dao.UserDao@10dba097
正在创建UserService:com.imooc.spring.ioc.service.UserService@481a15ff
setUdao = com.imooc.spring.ioc.dao.UserDao@10dba097
com.imooc.spring.ioc.dao.UserDao@10dba097
@Autowired可能遇到的问题:

如果IUserDao接口有两个实现类(即容器中有两个同类型的对象),  那么@Autowired注解按类型注入会失败. 解决办法:

  • 将不需要的一个实现类取消交给SpringIOC容器管理;
  • 在需要的那个接口实现类上面添加@Primary注解即可.

推荐按照名称进行注入

@Service
public class DepartmentService{
    /**
     * 1.@Resource设置name属性,则按照name在IoC容器中将bean注入
     * 2.@Resource未设置name属性
     * 2.1 以属性名作为bean  name在IoC容器中匹配bean,如有匹配则注入
     * 2.2 按属性名未匹配,则按类型进行匹配,同@Autowired,需加入@Primary解决类型冲突
     * 使用建议:在使用@Resource注解时推荐设置name或保证属性名与bean名称一致
     */
    @Resource(name = "userOracleDao")
    private IUserDao udao;
   
    //或者这种写法
    //@Resource
    //private IUserDao userOracleDao;
}其他元数据注解

注解说明
@Primary按类型装配时出现多个相同类型对象,拥有此注解对象优先被注入
@PostConstruct描述方法,相当于XML中init-method配置的注解版本
@PreDestroy描述方法,相当于XML中destroy-method配置的注解版本
@Scope设置对象的scope属性
@Value为属性注入静态数据

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
   
    <!--通知Spring IoC容器初始化时加载属性文件-->
    <context:property-placeholder location="classpath:config.properties"/>
   
</beans>
3.基于Java代码配置Bean


  • 完全摆脱XML的束缚,使用独立Java类管理对象与依赖
  • 注解配置相对分散,利用Java Config可对配置集中管理
  • 可以在编译时进行依赖检查,不容易出错
Java Config核心注解

注解说明
@Configuration描述类,说明当前类是Java Config配置类,完全替代XML文件
@Bean描述方法,方法返回对象将被IoC容器管理,beanId默认为方法名
@ImportResource描述类,加载静态文件,可使用@Value注解获取
@ComponentScan描述类,同XML的<context:component-scan>标签
创建Java类
public class UserDao {
  
}
public class UserService {

    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
​创建配置类
package com.imooc.spring.ioc;

import com.imooc.spring.ioc.dao.UserDao;
import com.imooc.spring.ioc.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 当前类是一个配置类,用于替代applicationContext.xml
public class Config {

    @Bean // Java Config利用方法创建对象,将方法返回对象放入容器,beanId=方法名
    public UserDao userDao() {
        return new UserDao();
    }

    @Bean
    public UserService userService() {
        return new UserService();
    }
}创建启动类
package com.imooc.spring.ioc;

import com.imooc.spring.ioc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringApplication {
    public static void main(String[] args) {
        // 基于Java Config配置IoC容器的初始化
        ApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);
        String[] ids = context.getBeanDefinitionNames();
        for (String id : ids) {
            System.out.println(id + ":" + context.getBean(id));
        }
    }
}结果如下
org.springframework.context.annotation.internalConfigurationAnnotationProcessor:org.springframework.context.annotation.ConfigurationClassPostProcessor@5a4aa2f2
org.springframework.context.annotation.internalAutowiredAnnotationProcessor:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6591f517
org.springframework.context.annotation.internalCommonAnnotationProcessor:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@345965f2
org.springframework.context.event.internalEventListenerProcessor:org.springframework.context.event.EventListenerMethodProcessor@429bd883
org.springframework.context.event.internalEventListenerFactory:org.springframework.context.event.DefaultEventListenerFactory@4d49af10
config:com.imooc.spring.ioc.Config$$EnhancerBySpringCGLIB$$216fe7e@279ad2e3
userDao:com.imooc.spring.ioc.dao.UserDao@58134517
userService:com.imooc.spring.ioc.service.UserService@4450d156
​属性注入
package com.imooc.spring.ioc;

import com.imooc.spring.ioc.dao.UserDao;
import com.imooc.spring.ioc.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 当前类是一个配置类,用于替代applicationContext.xml
@ComponentScan(basePackages = "com.imooc") // 此注解也会扫描该包及子包下其他组件
public class Config {

    @Bean // Java Config利用方法创建对象,将方法返回对象放入容器,beanId=方法名
    public UserDao userDao() {
        return new UserDao();
    }

    @Bean
    // 先按name尝试注入,name不存在则按类型注入
    public UserService userService(UserDao userDao) {
        UserService userService = new UserService();
        userService.setUserDao(userDao);
        return userService;
    }
}Spring Test测试模块


  • Spring Test是Spring中用于测试的模块
  • Spring Test对JUnit单元测试框架有良好的整合
  • 通过Spring Test可在JUnit在单元测试时自动初始化IoC容器
Spring与JUnit整合过程


  • Maven工程依赖spring-test
  • 利用@RunWith与@ContextConfiguration描述测试用例类
  • 测试用例类从容器获取对象完成测试用例的执行
加入依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>创建dao层
public class UserDao {
    public void insert() {
        System.out.println("新增数据");
    }
}创建service层
public class UserService {
    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
   
    public void createUser() {
        System.out.println("调用创建用户业务代码");
        userDao.insert();
    }
}创建配置文件
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.imooc.spring.ioc.dao.UserDao"/>
   
    <bean id="userService" class="com.imooc.spring.ioc.service.UserService">
        <property name="userDao" ref="userDao"/>
     </bean>
</beans>创建测试类
import com.imooc.spring.ioc.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

// 将JUnit4的执行权交由Spring Test,在测试用例执行前自动初始化IoC容器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTestor {
    @Resource
    private UserService userService;

    @Test
    public void testUserService() {
        userService.createUser();
    }
}
回复

使用道具 举报

0

主题

10

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2025-3-5 20:28:05 | 显示全部楼层
不错 支持下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表