Spring框架-IOC

1. Spring框架的介绍

Spring框架是一个开源的JavaEE应用程序

主要核心是IOC和AOP两大技术

  • IOC:Inversion of Control, 控制反转。它是通过将控制权从应用程序中移出,使得对象的创建和管理由框架来完成,从而降低系统间的耦合度。
  • DI:Dependency Injection, 依赖注入。它是一种设计模式,属于控制反转的一部分。其基本思想是将对象的依赖(即它所需要的其他对象)通过外部注入的方式提供,而不是由对象自己创建或查找。这有助于减少类之间的耦合,提高代码的可测试性、可维护性和灵活性。
  • AOP:Aspect-Oriented Programming, 面向切面编程。它是一种编程范式,旨在将横切关注点(如日志、事务处理、安全控制等)从主业务逻辑中分离出来,使得这些功能可以独立开发、测试和维护。

Spring官网:spring.io

目前学习的是:Spring Framework

2. Spring的作用

Dao层:

        JDBC操作。对应框架:MyBatis

Service层:

        Spring框架不是针对service层业务逻辑,service层没哟适合的框架

Controller层:

        Servlet(接收请求,响应数据,地址配置,页面转发)

        对应框架:Spring MVC

3. Spring框架搭建

3.1 新建一个maven项目

3.2 去MVN Repository官网导入Spring Context依赖坐标

 <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.2.1</version>
        </dependency>
</dependencies>

3.3 新建service.UserService (Bean类)

package com.gtc.service;
​
public class UserService {
    public void test(){
        System.out.println("UserService Test...");
    }
}

3.4 在resources文件目录下创建spring.xml配置文件

在Spring框架中,spring.xml是Spring配置文件的标准格式,通常用于配置Spring的Bean,即对象的创建、初始化、依赖注入等。通过spring.xml,我们可以定义Spring容器需要管理的所有对象及其属性和行为。

<?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">
     <!--
        id: bean标签的唯一标识,一般是对应的JavaBean对象名称的首字母小写
        class: JavaBean对象的类路径 (包名+类名)
    -->
    <bean id="userService" class="com.gtc.service.UserService"></bean>
</beans>

注意:这是Spring框架定义好的格式。

3.5 新建test.Starter01来测试

package com.gtc.test;
​
import com.gtc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class Starter01 {
    public static void main(String[] args) {
        // 得到Spring的上下文环境
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 通过id属性值得到指定的bean对象 (传统方法需要自己new)
        UserService userService = (UserService) ac.getBean("userService");
        // 调用实例化好的javabean对象中的方法
        userService.test();
    }
}

new UserService()的过程交给IOC去做了

4. Spring IOC 手动注入

手动实例化与外部引入

示例1:

public class UserService{
    UserDao userDao = new UserDao();
}

示例2:

public class UserService{
    private UserDao userDao;
    public UserService(UserDao userDao){
        this.userDao = userDao;
    }
}

对比发现:示例二中对于UserDao对象的创建并没有像示例一那样主动的去实例化,而是通过带参方法形式将UserDao传入过来,从而实现UserService对UserDao类的依赖

而实际创建对象的幕后对戏那个即是交给了外部来创建。

4.1 set方法注入

四个文件: UserDao.java, UserService.java, spring.xml, Start01.java

  • UserDao.java: Bean对象

  • UserService: Bean对象

  • spring.xml:配置文件

  • Start01.java: 测试文件

案例需求:UserService类中要使用UserDao类

// UserDao的Bean对象
package com.gtc.dao;
public class UserDao {
    public void test(){
        System.out.println("UserDao Test...");
    }
}
package com.gtc.service;

import com.gtc.dao.UserDao;
import com.sun.deploy.panel.IProperty;

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

public class UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    // 常用对象String(日期类型)
    private String host;
    public void setHost(String host) {
        this.host = host;
    }
    // 基本类型
    private Integer port;
    public void setPort(Integer port) {
        this.port = port;
    }

    // List集合
    private List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    // Set集合
    private Set<String> set;
    public void setSet(Set<String> set) {
        this.set = set;
    }
    // Map对象
    private Map<String, Object> map;
    public void setMap(Map<String, Object> map) {
        this.map = map;
    }
    // 属性Properties对象
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    
    public void test(){
        System.out.println("UserService Test...");
        userDao.test();
        System.out.println(host);
        System.out.println(port);
        // 遍历List集合
        for (String a : list){
            System.out.println(a);
        }
        // 遍历Set集合
        for (String a : set){
            System.out.println(a);
        }
        // 遍历Map
        for (Map.Entry<String, Object> entry : map.entrySet()){
            System.out.println("MapKey = " + entry.getKey() + ", MapValue = " + entry.getValue());
        }
        // 遍历Properties
        for (String key : properties.stringPropertyNames()){
            System.out.println("ProKey = " + key + ", ProValue = " + properties.getProperty(key));
        }
    }
}
<?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">

    <!--
        Set方法注入(通过property属性注入):
            name: bean对象中属性字段的名字
            ref: 指定bean标签的id属性值
    -->
    <bean id="userService" class="com.gtc.service.UserService">
        <!--JavaBean对象-->
        <property name="userDao" ref="userDao"></property>
        <!--常用类型String-->
        <property name="host" value="127.0.0.1"></property>
        <!--基本类型Integer-->
        <property name="port" value="8080"></property>
        <!--List集合-->
        <property name="list">
            <list>
                <value>List上海</value>
                <value>List杭州</value>
                <value>List深圳</value>
            </list>
        </property>
        <!--Set集合-->
        <property name="set">
            <list>
                <value>Set上海</value>
                <value>Set杭州</value>
                <value>Set深圳</value>
            </list>
        </property>
        <!--Map对象-->
        <property name="map">
            <map>
                <entry>
                    <key><value>周杰伦</value></key>
                    <value>晴天</value>
                </entry>
                <entry>
                    <key><value>林俊杰</value></key>
                    <value>江南</value>
                </entry>
                <entry>
                    <key><value>陈奕迅</value></key>
                    <value>单车</value>
                </entry>
            </map>
        </property>
        <!--Properties属性对象-->
        <property name="properties">
            <props>
                <prop key="bj">properties北京</prop>
                <prop key="sh">properties上海</prop>
                <prop key="hz">properties杭州</prop>
            </props>
        </property>
    </bean>

    <bean id="userDao" class="com.gtc.dao.UserDao"></bean>
    
</beans>
// Start01.java测试文件
package com.gtc;
​
import com.gtc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class Start01 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.test();
    }
}

得到的输出:

UserService Test...
UserDao Test...
127.0.0.1
8080
List上海
List杭州
List深圳
Set上海
Set杭州
Set深圳
MapKey = 周杰伦, MapValue = 晴天
MapKey = 林俊杰, MapValue = 江南
MapKey = 陈奕迅, MapValue = 单车
ProKey = bj, ProValue = properties北京
ProKey = sh, ProValue = properties上海
ProKey = hz, ProValue = properties杭州

4.2 构造器注入

注:需提供带参构造器

package com.gtc.dao;

public class UserDao02 {
    public void test(){
        System.out.println("UserDao02 Test...");
    }
}
package com.gtc.service;

import com.gtc.dao.UserDao02;

/**
 * 构造器方法注入
 *  需要提供带参构造
 */
public class UserService02 {
    private UserDao02 userDao02;

    /* 构造器注入 */
    public UserService02(UserDao02 userDao02) {
        this.userDao02 = userDao02;
    }

    public void test(){
        System.out.println("UserService02 test...");
        userDao02.test();
    }
}
<?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">

    <!--
        构造器注入:
            设置构造器所需要的参数
            通过constructor-arg标签设置构造器的参数
                name: 属性名称
                ref: 要注入的bean对象对应的bean标签的id属性值
    -->
    <bean id="userService02" class="com.gtc.service.UserService02">
        <constructor-arg name="userDao02" ref="userDao02"></constructor-arg>
    </bean>
    <bean id="userDao02" class="com.gtc.dao.UserDao02"></bean>
</beans>
package com.gtc.test;

import com.gtc.service.UserService;
import com.gtc.service.UserService02;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Starter02 {
    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring02.xml");
        UserService02 userService02 = (UserService02) beanFactory.getBean("userService02");
        userService02.test();
    }
}

4.3 静态工厂注入

将TypeDao类注入到TypeService类中,静态工厂的静态方法创建TypeDao,XML配置静态工厂。

package com.gtc.dao;

public class TypeDao {
    public void test(){
        System.out.println("TypeDao test...");
    }
}
package com.gtc.service;

import com.gtc.dao.TypeDao;

public class TypeService {
    private TypeDao typeDao;

    public void setTypeDao(TypeDao typeDao) {
        this.typeDao = typeDao;
    }
    public void test(){
        System.out.println("TypeService test...");
        typeDao.test();
    }
}
package com.gtc.factory;

import com.gtc.dao.TypeDao;

/**
 * 静态工厂注入
 */
public class StaticFactory {
    public static TypeDao createTypeDao(){
        return new TypeDao();
    }
}
package com.gtc.test;

import com.gtc.service.TypeService;
import com.gtc.service.UserService;
import com.gtc.service.UserService02;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Starter02 {
    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring02.xml");
        TypeService typeService = (TypeService) beanFactory.getBean("typeService");
        typeService.test();
    }
}

4.4 实例化工厂注入

5. Spring IOC 自动注入

注解方式注入Bean

        对于bean的注入,除了使用xml配置以外,可以使用注解配置。注解的配置,可以简化配置文件,提高开发速度,使程序看上去更简洁。对于注解的解释,Spring对于注解有专门的解释器,对定义的注解进行解析,实现对应bean对象的注入,通过反射技术实现

5.1 准备环境

将UserDao注入到UserService中

1. 准备UserDao类

package com.gtc.dao;

public class UserDao {
    public void test(){
        System.out.println("UserDao test...");
    }
}

2. 准备UserService类

package com.gtc.service;

import com.gtc.dao.UserDao;

import javax.annotation.Resource;

public class UserService {
    // 注入JavaBean对象
    @Resource
    private UserDao userDao;
    // set方法(也可以不要)
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void test(){
        System.out.println("UserService test...");
        userDao.test();
    }
}

3. 修改spring.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
           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/>
    <bean id="userDao" class="com.gtc.dao.UserDao"></bean>
    <bean id="userService" class="com.gtc.service.UserService"></bean>

</beans>

4. 测试

package com.gtc.test;

import com.gtc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App01 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.test();
    }
}

5.2 Resource注解

1. 注解默认通过属性字段名称查找对应的bean对象(属性字段名称与bean标签的id属性值一致)

2. 如果属性字段名称不一样,则会通过类型(Class)类型

3. 属性字段可以提供set方法,也可以不提供

4. 注解既可以声明在属性字段,也可以声明在set方法上

5. 可以设置注解的name属性,name属性值要与bean标签的id属性值一致

6. 当注入接口时,如果接口只有一个实现类,则正常实例化;如果接口有多个实现类,则需要使用name属性指定需要被实例化的bean对象

5.3 Autowired注解

1. 注解默认使用Class类型去查找bean对象,与属性字段名称没有关系

2. 属性字段可以提供set方法,也可以不提供

3. 注解可以声明在属性级别,也可以声明在set方法级别

4. 如果想要通过指定名称查找bean对象,需要结合@Qualifier使用,通过value属性值查找bean对象(value属性值必须要设置,且值要与bean标签的id属性值对应)

6. Spring IOC 扫描器

实际的开发中,bean的数量非常多,采用手动配置bean的方式已无法满足生产需要,Spring这时候同样提供了扫描的方式,对扫描的bean对象统一进行管理,简化开发配置,提高开发效率。

6.1 Spring IOC 扫描器的配置

Spring IOC 扫描器

作用:bean对象统一进行管理,简化开发配置,提高开发效率

1. 设置自动化扫描的范围:如果bean对象未在指定包范围,即时声明了注解,也无法实例化

2. 使用指定的注解(声明在类级别)bean对象的id属性默认是类的首字母小写

  • Dao层:@Repository
  • Service层:@Service
  • Controller层:@Controlloer
  • 任意类:@Component

(1) 准备TypeDao类

package com.gtc.dao;

import org.springframework.stereotype.Repository;

@Repository
public class TypeDao {
    public void test(){
        System.out.println("TypeDao test...");
    }
}

(2)配置IOC扫描器

<?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">

    <!-- Spring IOC 扫描器 -->
    <context:component-scan base-package="com.gtc"/>
</beans>

(3) 测试

package com.gtc.test;

import com.gtc.dao.TypeDao;
import com.gtc.service.AccountService;
import com.gtc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App01 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        TypeDao typeDao = (TypeDao) context.getBean("typeDao");
        typeDao.test();
    }
}

7. Bean的作用域与生命周期

7.1 Bean的作用域

默认情况下,我们从Spring容器中拿到的对象均是单例的,对于bean的作用域类型如下:

7.1.1 singleton作用域

 注意:lazy-init是懒加载,如果等于true时作用是指Spring容器启动的时候不会去实例化这个bean,而是在程序调用才去实例化。默认是false即Spring容器启动时实例化。

默认情况下,被管理的bean只会IOC容器中存在一个实例,对于所有获取该Bean的操作Spring容器将只返回同一个Bean。

容器在启动的情况下 (即获取Spring上下文的情况下) 就实例化所有singleton的bean对象,并缓存于容器中。

7.1.2 prototype作用域

Spring IOC容器在启动时,不会将bean对象实例化到容器中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值