Spring框架-IOC

1. Spring框架的介绍

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

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

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

Spring官网:spring.io

目前学习的是:Spring Framework

Spring框架-IOC_第1张图片

2. Spring的作用

Dao层:

        JDBC操作。对应框架:MyBatis

Service层:

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

Controller层:

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

        对应框架:Spring MVC

3. Spring框架搭建

3.1 新建一个maven项目

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

 
        
        
            org.springframework
            spring-context
            6.2.1
        

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容器需要管理的所有对象及其属性和行为。



     
    

注意:这是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 list;
    public void setList(List list) {
        this.list = list;
    }
    // Set集合
    private Set set;
    public void setSet(Set set) {
        this.set = set;
    }
    // Map对象
    private Map map;
    public void setMap(Map 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 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));
        }
    }
}



    
    
        
        
        
        
        
        
        
        
            
                List上海
                List杭州
                List深圳
            
        
        
        
            
                Set上海
                Set杭州
                Set深圳
            
        
        
        
            
                
                    周杰伦
                    晴天
                
                
                    林俊杰
                    江南
                
                
                    陈奕迅
                    单车
                
            
        
        
        
            
                properties北京
                properties上海
                properties杭州
            
        
    

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



    
    
        
    
    
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配置文件




    
    
    
    

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扫描器




    
    

(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作用域

Spring框架-IOC_第2张图片

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

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

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

7.1.2 prototype作用域

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

你可能感兴趣的:(spring,java,后端)