Spring IoC

2023-12-13 09:46:34

IOC控制反转:是一种设计理念,由代理人来创建和管理对象,消费者通过代理人来获取对象。IOC的目的是降低对象之间直接耦合。

加入IOC容器将对象统一管理,让对象关联变为弱耦合。
DI依赖注入,完成在程序运行过程中对象的创建与绑定。
DI在Java中利用反射技术实现对象注入。

Sping的含义:狭义Spring是指Spring框架,广义的Spring是指Spring生态体系。
Spring框架的核心是IOC容器和AOP面向切面编程。
Spring IOC负责创建和管理系统对象,并在此基础上扩展功能
基于配置实现应用程序的可维护性和可扩展性
在这里插入图片描述
三种配置方式:

  1. 基于XML配置Bean
  2. 基于注解配置Bean
  3. 基于Java代码配置Bean

一、基于XML配置Bean

实例化Bean的三种方式:

  1. 基于构造方法对象实例化(默认、带参)
  2. 基于静态工厂实例化
  3. 基于工厂实例方法实例化

基于构造方法对象实例化

 <!--利用默认构造方法实例化Bean-->
    <bean id="apple1" class="com.io.spring.ioc.entity.Apple">
    </bean>
<!--利用带参构造方法实例化Bean-->
    <bean id="apple2" class="com.io.spring.ioc.entity.Apple">
        <!--通过参数名实例化对象-->
        <constructor-arg name="title" value="红富士"/>
        <constructor-arg name="color" value="红色"/>
        <constructor-arg name="origin" value="欧洲"/>
    </bean>
    
    <bean id="apple3" class="com.io.spring.ioc.entity.Apple">
        <!--通过索引实例化对象-->
        <constructor-arg index="0" value="红富士"/>
        <constructor-arg index="1" value="红色"/>
        <constructor-arg index="2" value="欧洲"/>
    </bean>

基于静态工厂实例化

/**
 * 静态工厂通过静态方法创建对象,隐藏创建对象的细节
 */
public class AppleStaticFactory {
    public static Apple createSweetApple(){
        Apple apple = new Apple();
        apple.setTitle("红富士");
        apple.setOrigin("欧洲");
        apple.setColor("红色");
        return apple;
    }
}
<!--    利用静态工厂获取对象-->
    <bean id="apple4" class="com.io.spring.ioc.factory.AppleStaticFactory"
            factory-method="createSweetApple"/>

基于工厂实例方法实例化

/**
 * 工厂方法创建对象是指IOC容器对工厂类进行实例化并调用对应对实例方法创建对象的过程
 */
public class AppleFactoryInstance {
    public Apple createSweetApple(){
        Apple apple = new Apple();
        apple.setTitle("红富士");
        apple.setOrigin("欧洲");
        apple.setColor("红色");
        return apple;
    }
}
<!--    利用工厂实例方法获取对象-->
    <bean id="factoryInstance" class="com.io.spring.ioc.factory.AppleFactoryInstance"/>
    <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>

Bean的id和name属性:
都是设置对象在IOC容器中唯一标识,两者在同一个配置文件中都不允许重复,多个配置文件中允许出现重复且新对象覆盖旧对象。
id要求更为严格,一次只能定义一个对象标识,name一次允许定义多个对象标识

<bean name="apple1,apple7" class="com.io.spring.ioc.entity.Apple"/>

在没有id和name的bean默认使用类名全称作为bean标识

路径表达式用法:
在这里插入图片描述

对象依赖注入

依赖注入是指运行时将容器内对象利用反射赋值给其他对象
对象注入的方法:

  1. 基于setter方法注入对象
<!--IOC容器自动利用反射机制运行时调用setXXX方法为属性赋值-->
<bean id="sweetApple" class="com.io.spring.ioc.entity.Apple">
        <!--利用value设置静态值-->
        <property name="title" value="红富士"></property>
        <property name="origin" value="欧洲"></property>
        <property name="color" value="红色"></property>
</bean>
<bean id="andy" class="com.io.spring.ioc.entity.Child">
       <!--利用ref注入依赖对象-->
       <property name="name" value="安迪"></property>
       <property name="apple" ref="rdApple"></property>
</bean>
  1. 基于构造方法注入对象
<bean id="andy" class="com.io.spring.ioc.entity.Child">
		<!--利用ref注入依赖对象-->
        <constructor-arg name="name" value="安迪"/>
        <constructor-arg name="apple" ref="sourApple"/>
</bean>

注入集合对象:

public class Company {
    private List<String> rooms;
    private Map<String,Computer> computers;
    private Properties info;
    ...
<bean id="company" class="com.spring.ioc.entity.Company">
        <property name="rooms">
        //生成ArrayList对象
            <list>
                <value>2001-总裁办</value>
                <value>2003-总经理办公室</value>
                <value>2010-研发部会议室</value>
            </list>
        </property>
        <property name="computers">
        //生成LinkedHashMap对象
            //<map>
            //    <entry key="dev-88172" value-ref="c1"/>
            //</map>
            <map>
            	<entry key="dev-88172">
					<bean class="com.spring.ioc.entity.Computer">
        				<constructor-arg name="brand" value="联想"/>
        				<constructor-arg name="type" value="台式机"/>
        				<constructor-arg name="sn" value="8389283012"/>
        				<constructor-arg name="price" value="3085"/>
    				</bean>
				</entry>
            </map>
        </property>
        <property name="info">
        //Properties类似于map,但是key和value都必须是String类型
            <props>
                <prop key="phone">010-12345678</prop>
                <prop key="address">XXXXXXXXX</prop>
                <prop key="website">http://www.xxx.com</prop>
            </props>
        </property>
</bean>

需要去重时使用set


public class Company {
    private Set<String> rooms;
    ...
<bean id="company" class="com.spring.ioc.entity.Company">
        <property name="rooms">
        //生成LinkedHashSet对象
            <set>
                <value>2001-总裁办</value>
                <value>2003-总经理办公室</value>
                <value>2010-研发部会议室</value>
                 <value>2010-研发部会议室</value>
            </set>
        </property>
    </bean>

运行

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);
        System.out.println(company.getInfo().getProperty("address"));
    }
}

查看容器内对象

//获取容器内所有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
        System.out.println(context.getBean("com.spring.ioc.entity.Computer#1", Computer.class));
        System.out.println(context.getBean("com.spring.ioc.entity.Computer#0", Computer.class));
      

bean scope属性:决定对象何时被创建与作用范围
设置bean scope属性将影响容器内对象的数量
默认情况下bean会在IoC容器创建后自动实例化,全局唯一

scope="prototype" //允许存在多个实例
在这里插入图片描述
在这里插入图片描述

bean的生命周期:
在这里插入图片描述

创建对象-设置属性-执行init()方法-执行业务方法-执行destroy()方法释放对象相关资源

//执行销毁IOC容器的方法
((ClassPathXmlApplicationContext)context).registerShutdownHook();

二、基于注解配置IoC容器

基于注解配置IoC容器

优势:
摆脱繁琐的XML形式的bean与依赖注入配置
基于“声明式”的原则,更适合轻量级的现代企业应用
让代码可读性变好,研究人员拥有更好的开发体验

三类注解:

  • 组件类型注解-声明当前类的功能和职责
  • 自动装配注解-根据属性特征自动注入对象
  • 元数据注解-更细化的辅助IoC容器管理对象的注解

四类组件类型注解:
在这里插入图片描述

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:component-scan base-package="spring.ioc"/>

</beans>

两类自动装配注解:
在这里插入图片描述

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

	//@Autowired
    //如果装配注解放在set方法上,则自动按类型/名称对set方法参数进行注解
    //所以一般无set方法
    //public void setUdao(UserDao udao) {

@Autowired默认按照类型装配,默认情况下要求依赖对象必须存在。

使用@Autowired进行属性注入时,如果该类型有多个实现类,可以在一个实现类上使用@Primary,表示优先使用该类。

 /**
     * 1.@Resource设置name属性,则按照name在IoC容器中将bean注入
     * 2.@Resource未设置name属性
     * 2.1 以属性名作为bean name在IoC容器中匹配bean,如有匹配到就注入
     * 2.2 按属性名未匹配,则按类型进行匹配,同@Autowired,需要加入@Primary解决类型冲突
     * 使用建议:在使用@resource对象时推荐设置name,或保证属性名与bean name一致
     */
    //@Resource(name="userOracleDao")
    //private IUserDao udao;
    @Resource
    private IUserDao udao;

    public void joinDepartment(){
        System.out.println(udao);
    }

@Resource有两个属性:name和type,Spring将@Resource注解的name属性解析为bean的名称,type属性解析为bean的类型,默认按照名称进行装配,名称可以通过name属性进行指定。

@Resource和@Autowired的区别:

  • 都可以用来装配bean,都可以写在字段或setter方法上。
  • @Resource默认按照名称装配,如果没有指定name属性,注解写在字段上,默认时取字段名作为名称查找,如果注解写在setter方法上默认是取属性的名称进行装配,当找不到名称匹配的bean时才按照类型进行匹配,如果name属性一旦指定,只会按照名称装配。
  • @Resource的装配顺序:(1)如果同时指定了name和type,则寻找唯一匹配的bean进行装配;(2)如果指定了name,则查找名称(id)匹配的bean进行装配;(3)如果指定了type,查找类型匹配的唯一bean进行装配,找不到或者找到多个都抛出异常;(4)如果没指定name或type,自动按照byName方式装配,没匹配到按照原始类型匹配
  • @Autowired允许null值,@Autowired(requied=false)
  • @Autowired使用名称装配要结合@Qualifier,@Autowired @Qualifier(“test”),解决@Service重名问题。

元数据注解:
在这里插入图片描述

@Primary
@Scope("prototype") //设置单例/多例,和XML中bean scope完全相同
public class UserService {
	@Value("${metadata}") //读取config.properties的metadata属性值
    private String metaData;
	@PostConstruct //XML中bean init-method完全相同
    public void init(){
        System.out.println("初始化UserService对象,metaData="+metaData);
    }
}

@Value使用
1)创建配置文件config.properties,设置属性名=属性值
2)在applicationContext.xml中通过placeholder加载配置文件
<context:property-placeholder location="classpath:config.properties"/>
3)在代码中使用@Value("${属性名}")来给属性设置静态值

三、基于Java Config配置IoC容器

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

Java Config核心注解:
在这里插入图片描述

@Configuration //说明当前类是一个配置类,用于替代applicationContext.xml
@ComponentScan(basePackages = "spring.ioc")
public class Config {
    @Bean //Java Config利用方法创建对象,将方法返回对象放进容器,beanId=方法名
    @Primary
    public UserDao userDao(){
        UserDao userDao = new UserDao();
        System.out.println("已创建"+userDao);
        return userDao;
    }
    @Bean
    //通过参数进行依赖注入
    //先按name尝试注入,name不存在时按类型注入
    public UserService userService(UserDao userDao, EmployeeDao employeeDao){
        UserService userService = new UserService();
        System.out.println("已创建"+userService);
        userService.setUserDao(userDao);
        System.out.println("调用setUserDao:"+userDao);
        System.out.println("调用employeeDao:"+employeeDao);
        return userService;
    }
    @Bean
    @Scope("prototype")
    public UserController userController(UserService userService){
       UserController userController = new UserController();
       System.out.println("已创建"+userController);
       userController.setUserService(userService);
        System.out.println("调用setUserService:"+userService);
       return userController;
    }
}

Spring Test测试模块

Spring Test对JUnit单元测试框架有良好的整合。
通过Spring Test可以在JUnit单元测试时自动初始化IoC容器。

Spring与JUnit4整合过程:

  1. Maven工程依赖spring-test和junit
  2. 利用@RunWith和@ContextConfiguration描述测试用例类
  3. 测试用例类从容器获取对象完成测试用例执行
@RunWith(SpringJUnit4ClassRunner.class) //将Junit4的执行权交给Spring Test,在测试用例执行前自动初始化IoC容器
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})//在IoC容器初始化过程中,通知要加载那个配置文件
public class SpringTestor {
    @Resource
    private UserService userService;
    @Test
    public void testUserService(){
        userService.createUser();
    }
}

文章来源:https://blog.csdn.net/nefss_/article/details/134138356
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。