Spring-IOC

一、spring是什么?

spring是开源Java软件框架,利用这套框架可以快速搭建java软件



二、spring框架两个核心功能

1.IOC/ID

2.AOP

1.1 IOC

1.主动控制:由应用程序主动控制管理“对象组件”。适合管理创建简单的对象

2.控制反转:由外部容器环境(框架)创建管理“对象组件”交给应用程序使用。适合管理创建过程复杂的对象。从对象使用者的角度看是简单的

1.2 Java Bean

  为了规范Java类的定义,Java提供Java Bean规范,所谓的javabean规范就是约定Java类的定义规则,使程序一致,方便使用和交流。其约定如下:

  1. 需要定义包package
  2. 有无参的构造器
  3. 需要实现序列化接口
  4. 包含使用 getXxx setXxx 声明的“Bean属性” xxx
  •         a.Bean属性(Bean Property)就是指 setXxx getXxx方法
  •         b.对象属性(Object Field)是指对象的实例变量

1.3 JUnlt测试Spring

  JUnlt提供了@Before和@After注解,这两个注解声明的方法可以在测试案例方法之前和之后执行。

  测试spring时候需要spring容器的代码冗长麻烦,利用JUnit的@Before和@After注解声明方法,封装spring的初始化和销毁方法,可以一劳永逸的解决spring的初始化问题

1.4 主键扫描

1.4.1 spring主键扫描

spring提供主键扫描注解,利用组件扫描注解和主键配合,可以自动扫描包空间自动创建Bean对象,减少编码,提高编程效率

1.4.2 spring提供多种组件注解

spring提供了多种注解,用于程序中不同用途的组件标注,这些注解名字不同但是其作用相同,这些包括:

  • @Controller,控制器组件
  • @Service,业务层组件
  • @Component,通用组件

  使用组件@Component注解声明类

package cn.tedu.pojo;

import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Component //spring 在组件扫描时候会找到标注@Component的类
//将类创建为对象,并且其Bean ID为“DemoBean”
public class DemoBean implements Serializable { //实现序列化:防止在进入缓存阶段时,程序出错
    @Override
    public String toString() {
        return "DemoBean";
    }
}

  在配置类上使用注解扫描功能

package cn.tedu.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Configuration  //此类为配置文件
@ComponentScan(basePackages = "cn.tedu.pojo") //指定被扫描的包
public class Config {
    @Bean
    /**
     * 告诉spring在启动时候,加载被@#Bean标准的方法
     * 返回值是spring创建的对象,方法名是Bean的ID
     * */
    public Demo bean(){
        return new Demo();
    }
}

  测试

@Test
    public void testDemoBean(){
        /** 测试组件扫描功能*/
        DemoBean bean = ctx.getBean("demoBean", DemoBean.class);
        System.out.println(bean);
    }

  由于剩下两个组件的使用方式类似,除了名字不同,作用一样,就不一一举例

1.4.3自定义组件ID

  在使用组件扫描功能时候@Component注解可以添加属性,自定义组件的ID。定义了自定义组件ID以后,基于可以使用新的ID管理组件,原有的默认组件ID就不再有效。

package cn.tedu.pojo;

import org.springframework.stereotype.Controller;

/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Controller("controller") //定义此ID,则基于此ID管理组件
public class DemoController {
    @Override
    public String toString() {
        return "DemoController";
    }
}

开发中很少这么设定Bean ID,尽量采用默认规则,这样有助于减少代码,减少错误

1.5 Spring Bean管理

1.5.1 Bean的作用域

  spring针对对象的不同作用范围设计看Bean作用域,spring的Bean常用的作用域用两个singeton(单例),prototype(原型):

  spring中默认情况下Bean组件作用域是单例,也就是说任何时候调用getBean方法获得的对象都是同一个实例。这么设计优点是一个Bean可以被复用,提高了内存资源利用率,但是也有问题,每个对象状态都是不同的Bean就不合适

案例:

@Test
    public void testSingleton(){
        DemoBean bean1 = ctx.getBean("demoBean", DemoBean.class);
        DemoBean bean2 = ctx.getBean("demoBean", DemoBean.class);
        System.out.println(bean1==bean2);
        System.out.println(bean1.equals(bean2));
    }

运行结果:

初始化
true
true
19:46:03.576 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@41ee392b, started on Fri Oct 29 19:46:03 CST 2021
销毁

  在设置了@Scope("prototype")注解以后,Bean作用域是“原型”,此时是每次调用getBean都会创建一个对象实例

案例:

package cn.tedu.pojo;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Component
@Scope("prototype")
public class ExampleBean {
    @Override
    public String toString() {
        return "ExampleBean";
    }
}

测试案例:

@Test
    public void testPrototype(){
        ExampleBean bean1 = ctx.getBean("exampleBean", ExampleBean.class);
        ExampleBean bean2 = ctx.getBean("exampleBean", ExampleBean.class);
        System.out.println(bean1==bean2);
        System.out.println(bean1.equals(bean2));
    }


运行结果:

初始化
false
false
19:51:35.052 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@41ee392b, started on Fri Oct 29 19:51:34 CST 2021
销毁

//运行结果说明两个调用getBean方法得到的两个不同对象引用,也就是创建了多个对象实例

1.5.2 对象生命周期管理

  当使用Spring IOC后,Spring IOC提供了对象声明周期管理功能。你可以利用生命周期管理注解,标注到方法上,Spring就会创建对象,销毁对象时候执行相应的方法。这样就可以让Spring帮助管理对象的生命周期,充分利用IOC容器提供的对象生命周期管理功能

  Spring提供两种管理对象生命周期的方式:

测试案例1:@PostConstruct @PreDestroy

1.利用Maven导入javax.annotation注解

            <dependency>
                <groupId>javax.annotation</groupId>
                <artifactId>javax.annotation-api</artifactId>
                <version>1.0</version>
            </dependency>

2.声明Bean组件类型

package cn.tedu.pojo;

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.io.PrintWriter;
/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 *
 * 测试第一种管理对象生命周期的方式
 * 使用@Component注解管理Bean组件时候,使用
 */
@Component
public class FileLogger {
    public PrintWriter out;

    @PostConstruct
    public void open() throws IOException {
        out = new PrintWriter("Demo.txt");
        System.out.println("打开文件Demo.txt");
    }

    @PreDestroy
    public void close(){
        out.close();
        System.out.println("关闭文件Demo.txt");
    }
}

3.测试案例:

@Test
    public void testPostConstruct(){
        FileLogger fileLogger = ctx.getBean("fileLogger", FileLogger.class);
        fileLogger.out.println("Hi");
        fileLogger.out.println("Test!");
    }

测试结果

打开文件Demo.txt
20:40:10.537 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'logger'
打开文件Demo.txt
20:40:10.557 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean'
初始化
20:40:10.594 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@668bc3d5, started on Fri Oct 29 20:40:10 CST 2021
关闭文件Demo.txt
关闭文件Demo.txt
销毁

Process finished with exit code 0

测试案例2: initMethod  destroyMethod

 1.编程被测试的类型

package cn.tedu.pojo;

import java.io.IOException;
import java.io.PrintWriter;
/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
public class DemoLogger {
    public PrintWriter out;
    public void open() throws IOException {
        out = new PrintWriter("Demo.txt");
        System.out.println("打开文件Demo.txt");
    }
    public void close(){
        out.close();
        System.out.println("关闭文件Demo.txt");
    }
}

2.在Config类中配置信息:

@Bean(initMethod = "open",destroyMethod = "close")
    public DemoLogger logger(){
        return new DemoLogger();
    }

3.编写测试案例:

@Test
    public void testDemoLogger(){
        DemoLogger logger = ctx.getBean("logger", DemoLogger.class);
        logger.out.println("Hi");
        logger.out.println("Test!");
    }

测试结果:

打开文件Demo.txt
20:50:04.550 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'logger'
打开文件Demo.txt
20:50:04.568 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean'
初始化
20:50:04.599 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@668bc3d5, started on Fri Oct 29 20:50:04 CST 2021
关闭文件Demo.txt
关闭文件Demo.txt
销毁

/**
 * 刷新项目文件目录后可以在测试文件DemoLogger.txt中找到输出结果:Hi Test!
 * 显然在控制台上出现了上一个案例中的“打开文件Demo.txt”信息,原因是Spring采用“立即初始化”
 * 方式创建了对象 
 */

测试案例:测试  @Scope("prototype")时候destroyMethod不生效现象

 1.5.3 懒惰初始化

在@Component注解下加了@Lazy注解

package cn.tedu.pojo;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Component
@Lazy
public class Person {
    public Person(){
        System.out.println("创建了Person");
    }

    @Override
    public String toString() {
        return "良子哥";
    }
}

测试案例:

@Test
    public void testPerson(){
        Person person = ctx.getBean("person", Person.class);
        System.out.println(person);  //区别在于调用和不调用person的结果
        System.out.println("OK");
    }

测试结果:

  不调用时:

   调用时

在@Bean下加@Lazy注解

 @Bean
    @Lazy
    public Student student(){
        return new Student();

测试案例:

@Test
    public void testStudent(){
        Student student = ctx.getBean("student", Student.class);
        System.out.println(student);  //区别在于调用或者不用调用student的结果
        System.out.println("OK");
    }

 测试结果:

    调用情况下:

 

  不调用情况下:

 

1.5.3 @Import 

当公司两个程序员要合并配置文件时。一般情况下会出现配置文件覆盖的情况,这时就需要人工合并配置文件,将里面的Bean对象放到一起,实现合并。但是人工合并却很费时间,浪费人才资源。这时出现了该注解。可以将两人的配置文件合并在一起。

案例:

创建一个新的配置文件SysConfig配置文件(在不同包下)

package cn.tedu.sys;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;

/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Configuration
/**
 * 系统管理模块配置信息
 * */
public class SysConfig {
    @Bean
    public Date myDate(){
        return new Date();
    }
}

 将上面的配置文件导入到Config配置文件中

package cn.tedu.demo;

import cn.tedu.pojo.DemoLogger;
import cn.tedu.pojo.Student;
import cn.tedu.sys.SysConfig;
import org.springframework.context.annotation.*;

/**
 * @Author Mr WeiLiang
 * @Date 2021/8/5 0005 09:22
 * @Version 1.0
 */
@Configuration  //此类为配置文件
@ComponentScan(basePackages = "cn.tedu.pojo") //指定被扫描的包
@Import({cn.tedu.sys.SysConfig.class})  //合并SysConfig配置文件,如果有多个,在后面 
                                        //加逗号继续添加
public class Config {
    @Bean(initMethod = "open",destroyMethod = "close")
    //@Scope("prototype")
    public DemoLogger demoLogger(){
        return new DemoLogger();
    }
    @Bean
    /**
     * 告诉spring在启动时候,加载被@#Bean标准的方法
     * 返回值是spring创建的对象,方法名是Bean的ID
     * */
    public Demo bean(){
        return new Demo();
    }

    @Bean
    @Lazy
    public Student student(){
        return new Student();
    }
}

测试案例

@Test
    public void testMyDate(){
        Date date = ctx.getBean("myDate", Date.class);
        System.out.println(date);
    }

测试结果

打开文件Demo1.txt
13:32:55.835 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean'
初始化
Sat Oct 30 13:32:55 CST 2021  //系统当前时间
13:32:55.866 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@668bc3d5, started on Sat Oct 30 13:32:55 CST 2021
关闭文件Demo1.txt
关闭文件Demo.txt

//可以调用SysConfig中的Bean方法,输出当前系统的时间




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值