Spring 框架两大核心机制之一IoC

一、Spring 框架两大核心机制——IoC

  • 设计思想:IoC(控制反转)在这里插入图片描述
  • 手段:DI(依赖注入)
    在这里插入图片描述

二、Spring-Bean依赖注入

1、设计原则:依赖倒置原则

1、高层模块不应该依赖底层模块,二者都应该依赖抽象。

2、抽象不应该依赖细节,细节应该依赖抽象。

3、依赖倒置的中心思想是面向接口编程

4、依赖倒置原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础搭建的架构要稳定的多。

5、使用接口或抽象类的目的是指定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类来完成。

经典案例:高层模块依赖于底层实现模块

/*高层模块*/
public class Driver {
  //司机的主要职责就是驾驶汽车
   public void drive(Benz benz){
      benz.run();
  }
}
/*底层实现模块*/
public class Benz {
    //汽车肯定会跑
    public void run(){
    System.out.println("奔驰汽车开始运行...");
 }
}

驾驶人依赖于开奔驰,而不会开宝马

/*底层实现模块*/
public class BMW {
    //宝马车当然也可以开动了
   public void run(){
    System.out.println("宝马汽车开始运行...");
  }
}
  • 接口传递
  • 构造方法传递
  • setter方法传递
  • 1、接口传递对象

    高层模块依赖于对象实现的接口,而对象通过实现接口方法,不与高层模块建立依赖关系。

    //将汽车模块抽象为一个接口:可以是奔驰汽车,也可以是宝马汽车
    public interface ICar {
          //是汽车就应该能跑
          public void run();
    }
    
    public class Benz implements ICar{
        //汽车肯定会跑
        public void run(){
            System.out.println("奔驰汽车开始运行...");
      }
    }
    
    public class BMW implements ICar{
       //宝马车当然也可以开动了
       public void run(){
          System.out.println("宝马汽车开始运行...");
       }
    }
    
    /*高层模块依赖对象接口*/
    public class Driver implements IDriver{
        //司机的主要职责就是驾驶汽车
        public void drive(ICar car){
            car.run();
        }
    }
    
  • 2、构造方法传递对象

    //将司机模块抽象为一个接口
    public interface IDriver {
         public void drive();
    }
    
    public class Driver implements IDriver{
        //有参构造器注入依赖
        private ICar car;
        public Driver(ICar car){
          this.car = car;
        }
    
        public void drive(){
            this.car.run();
        }
    }
    
  • 3、setter方法传递对象

    public class Driver implements IDriver{
      private ICar car;
      /*setter方法注入依赖*/
      public void setCar(ICar car){
        this.car = car;
      }
    
      public void drive(){
        this.car.run();
      }
    }
    

2、Bean的作用

  • 什么是Bean?

Spring Bean是被实例的,组装的被Spring 容器管理的Java对象。

Spring 容器会自动完成@Bean对象的实例化。

创建应用对象之间的协作关系的行为称为:装配(wiring),这就是依赖注入的本质。

Bean是把需要被调用实例化的对象由Spring容器管理,相当于定义一个组件,这个组件是用于具体实现某个功能的。

  • 传统的实例化对象:
//new 一个person对象
Person person = new Person();
//实例化person类的行为说话
Say say = new Say();
person.setName("小明");
person.behavier(say);

//new一个service
UserSevice userservice =  new UserService();
//调用servie方法
userService.login();

在传统的程序开发中,需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动new出来的。

通过Bean的依赖注入,让Spring控制对象的实例化,开发者即可直接使用Bean的属性或者方法,省去了new对象的注入,降低代码间的依赖关系,使对象开箱即用。

  • 通过 IoC 容器创建对象,把Bean添加到Spring组件中

    Spring三种装配bean的方式

    1.在XML中进行显示配置
    2.使用Java代码进行显示配置
    3.隐式的bean发现机制和自动装配
    推荐方式: 3>2>1

3、基于XML装配bean的三种实例化方式

实例化方式

首先我们应该知道Spring中基于XML装配bean时有三种实例化方式,分别是

  1. 默认构造
  2. 静态工厂
  3. 实例工厂
1)默认构造

接口加入组件,成为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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
	<bean name=“userService” class="com.shanmu.UseServiceImpl"></bean>
    
</beans>

UseServiceImpl实现UserService接口

public class UseServiceImpl implements UserService{

	@Override
	public void saveUser(){
		System.out.print("i am a user");
	}
}

调用实现类的方法saveUser()

public static void main(String[] args){
    //不采用spring
    UserService userService =new UseServiceImpl();
    userService.saveUser();

    //采用spring Bean默认构造方法
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    UserService userService =(UserService)context.getBean("userService");
    userService.saveUser();
}
2)静态工厂

静态工厂是用于生成实例对象的,工厂类中的所有方法必须是静态的
首先我们需要一个工厂类,这个工厂类中有一个静态方法帮我们得到了UseServiceImpl实例,所以我们后面只需要直接调用静态方法即可
下面是工厂类,通过这个类我们就可以得到UserService

public class MyBeanFactory(){
	public static UserService createService(){
		return new UserServiceImpl();
	}
}

xml中注册Bean组件

<bean name=“userService” class="com.*.MyBeanFactory" factory-method="CreateService">
</bean>

调用静态工厂类方法

public static void main(String[] args){
    //不采用spring
    UserService userService=MyBeanFactory.createService();
    userService.saveUser();

    //采用spring Bean默认构造方法
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    UserService userService =(UserService)context.getBean("userService");
    userService.saveUser();
}
3)实例工厂

实例工厂一样是需要有一个工厂类,但是与静态工厂不一样的地方在于里面的方法都是“非静态的”,所以我们需要得到一个工厂类的实例才能得到一个UseServiceImpl实例

public class MyBeanFactory(){
	public UserService createService(){
		return new UserServiceImpl();
	}
}

需要在spring.xml中这样配置

<!--先对工厂类实例化注入到Bean中-->
<bean name=“myBeanFactory” class="com.*.MyBeanFactory">
</bean>
<!-- 引用工厂类的Bean方法-->
<bean name=“userService” factory-bean="myBeanFactory" factory-method="createService">
</bean>

调用工厂方法需先实例化工厂对象,在进行方法调用

public static void main(String[] args){
    //不采用spring
    MyBeanFactory myBeanFactory=new MyBeanFactory();//实例化工厂
    UserService userService=myBeanFactory.createService();//调用实例化工厂返回实现类
    userService.saveUser();

    //采用spring默认构造方法
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    UserService userService =(UserService)context.getBean("userService");
    userService.saveUser();
}

4、基于注解@Component

自动装配优势:

  • 便利,自动化装配,隐式配置代码量少。

自动装配限制:

  • 基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。
  • 装配依赖中若是出现匹配到多个bean(出现歧义性),装配将会失败。
4.1 Spring实现自动装配两个步骤:
  • 组件扫描(component scanning):Spring会扫描@Component注解的类,并会在应用上下文中为这个类创建一个bean。
  • 自动装配(autowiring):Spring自动满足bean之间的依赖。

使用到的注解:

  • @Component:表明这个类作为组件类,并告知Spring要为这个类创建bean。默认bean的id为第一个字母为小写类名,可以用value指定bean的id。

  • @Configuration:代表这个类是配置类。

  • @ComponentScan:启动组件扫描,默认会扫描所在包以及包下所有子包中带有@Component注解的类,并会在Spring容器中为其创建一个bean。可以用basePackages属性指定包。

  • @RunWith(SpringJUnit4ClassRunner.class):以便在测试开始时,自动创建Spring应用上下文。

  • @ContextConfiguration:指定类加载配置。

    相当于new一个**AnnotationConfigApplicationContext(config.class)**配置类加载Spring的应用上下文

  • @Autowired:将一个类的依赖bean装配进来。

    @Autowired
    CDPlayer cdPlayer;
    
    public class MediaPlayer implements CDPlayer {
    
        private final CDDisk cdDisk;
    
        @Autowired
        public MediaPlayer(CDDisk cdDisk) {
            this.cdDisk = cdDisk;
        }
    }
    

定义功能类组件

@Component/*声明为Bean对象,相当于注册到Spring容器中的组件*/
public class HuaHua implements CDDisk {

    @Override
    public void sing() {
        String title = "烟火里的尘埃";
        String singer = "华晨宇";
        System.out.println(title + "_" + singer);
    }
}
@Component/*声明为Bean对象,相当于注册到Spring容器中的组件*/
public class MediaPlayer implements CDPlayer {

    /*Spring Ioc容器自动注入Bean依赖
    	--这里使用构造方法依赖注入*/
    private final CDDisk cdDisk;
    @Autowired
    public MediaPlayer(CDDisk cdDisk) {
        this.cdDisk = cdDisk;
    }

    @Override
    public void play() {
        cdDisk.sing();
    }
}

配置类

Spring会扫描@Component注解的类,并会在应用上下文中为这个类创建一个bean。

@Configuration//声明这是一个配置类
/*启动组件扫描,默认会扫描所在包以及包下所有子包中带有@Component注解的类,并会在Spring容器中为其创建一个bean。*/
@ComponentScan("注册Bean对象的包路径")
public class CDPlayerConfig {
}

引用Bean对象

  • 使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文

    AnnotationConfigApplicationContext作为Spring容器,接受输入一个配置类作为参数

public static void main(String[] args) {

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);//创建应用上下文指定配置类
    CDPlayer cdPlayer = context.getBean(CDPlayer.class);//获取Ioc容器中的Bean对象
    cdPlayer.play();
}
  • 自动装配**@Autowired**、注解声明指定类加载配置@ContextConfiguration
@ContextConfiguration(classes = CDPlayerConfig.class)//指定类加载配置
public class test2 {

    @Autowired
    CDPlayer cdPlayer;

    public void test() {
        cdPlayer.play();
    }
}

5、Java配置注册Bean

Java配置是通过@configuration和@Bean来实现的

@Configuration可理解为用spring的时候xml里面的标签

@Bean可理解为用spring的时候xml里面的标签

场景

尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化更为推荐,但是有时候行不通。比如引用第三方组件,没办法在它的类上添加@Component及@Autowired。所以就需要JavaConfig或者XML配置

JavaConfig是配置相关代码,不含任何逻辑代码。通常会将JavaConfig放到单独的包中。

优点:

  • 可以实现基本数据类型的值、字符串字面量、类字面量等注入。

使用到的注解:

  • @Bean:注解在方法上,声明当前方法的返回值为一个Bean。默认情况下配置后bean的id和注解的方法名一样,可以通过name属性自定义id。
  • @ImportResourse:将指定的XML配置加载进来
  • @Import:将指定的Java配置加载进来。
5.1 创建JavaConfig类
@Configuration
public class CDPlayerConfig {
}

使用@Configuration表明CDPlayerConfig是一个配置类

5.2 声明简单的bean
@Bean
public IMediaPlayer cdplayer(JayCompactDisc dis) {
    return new VCDPlayer(dis);
}

@Bean注解会告诉Spring将返回一个的对象注册为Bean

Spring上加@Bean注解的都是默认单例模式

默认情况下,@Bean的Id与带有@Bean的方法名一样。当然也可以通过@Bean的name属性指定额外的方法名。

5.3 Java配置和注解混合配置
  • 全局配置使用Java配置(如数据库配置、MVC相关配置)
    :将指定的Java配置加载进来。
5.1 创建JavaConfig类
@Configuration
public class CDPlayerConfig {
}

使用@Configuration表明CDPlayerConfig是一个配置类

5.2 声明简单的bean
@Bean
public IMediaPlayer cdplayer(JayCompactDisc dis) {
    return new VCDPlayer(dis);
}

@Bean注解会告诉Spring将返回一个的对象注册为Bean

Spring上加@Bean注解的都是默认单例模式

默认情况下,@Bean的Id与带有@Bean的方法名一样。当然也可以通过@Bean的name属性指定额外的方法名。

5.3 Java配置和注解混合配置
  • 全局配置使用Java配置(如数据库配置、MVC相关配置)
  • 业务Bean的配置使用注解配置(@Service、@Component、@Repository、@Cotroller)

文章部分转自:https://blog.csdn.net/aijiu1372/article/details/101990055?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值