129.【Spring 注解_IOC】(四)

简介: 129.【Spring 注解_IOC】

3.使用JSR250规范 (第四种)

(1).@PostConstruct 和 @PreDestroy

@PostConstruct:在bean创建完成并且属性值赋值完成后执行初始化;

@PreDestroy:在容器销毁bean之前,通知容器进行清理工作;

1.需要被注册的组件

package com.jsxs.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
 * @Author Jsxs
 * @Date 2023/8/16 15:37
 * @PackageName:com.jsxs.bean
 * @ClassName: Dog
 * @Description: TODO
 * @Version 1.0
 */
public class Dog {
    public Dog() {
        System.out.println("dog constructor...");
    }
    @PostConstruct   ⭐
    public void init() {
        System.out.println("dog 初始化中...");
    }
    @PreDestroy() ⭐
    public void destroy() {
        System.out.println("dog 销毁中...");
    }
}

2.配置类: 注册需要的组件

package com.jsxs.config;
import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import com.jsxs.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 * bean 创建 -> 初始化 -> 销毁的过程
 * 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 * 1. init-method="" destroy-method=""
 * 2. 构造(对象创建)
 * 单实列: 在容器启动的时候创建对象
 * 多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */
@Configuration
public class MainConfigOfLifeCycle {
    // 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。
    @Bean(value = "car", destroyMethod = "destroy", initMethod = "init")
    public Car car() {
        return new Car();
    }
    @Bean
    public Car01 car01() {
        return new Car01();
    }
    @Bean  ⭐
    public Dog dog(){
        return new Dog();
    }
}

3.测试

package com.jsxs.Test;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

4.BeanPostProcessor后置处理器 (第五种)

(1).BeanPostProcessor 后置处理器

后置处理器相当于在组件初始化之前做什么,初始化之后我们还做什么?

我们的Bean需要继承一个接口 BeanPostProcessor 并且完成两个方法。

在bean的初始化方法之前初始化方法之后进行一些处理工作。注意是初始化方法,和销毁方法没有一毛钱的关系。

初始化方法之前: 调用:postProcessBeforeInitialization()

初始化方法之后:调用:postProcessAfterInitialization()

即使没有自定义初始化方法,在组件创建前后,后置处理器方法也会执行。

1.注册我们的后置处理器

package com.jsxs.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
 * @Author Jsxs
 * @Date 2023/8/16 15:51
 * @PackageName:com.jsxs.bean
 * @ClassName: MyBeanPostProcessor
 * @Description: TODO  我们需要实现一个 BeanPostProcessor 接口,并且完成两个方法
 * @Version 1.0
 */
@Component ⭐
public class MyBeanPostProcessor implements BeanPostProcessor {  ⭐⭐
    /**
     * @param bean     新建组件的实列
     * @param beanName 新建组件实列的名字
     * @return 返回的是组件的信息
     * @throws BeansException
     */
    @Override  ⭐⭐⭐
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "----->" + bean);
        return bean;
    }
    /**
     * @param bean     新建组件的实列
     * @param beanName 新建组件实列的名字
     * @return  返回的是组件的信息
     * @throws BeansException
     */
    @Override ⭐⭐⭐⭐
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "----->" + bean);
        return bean;
    }
}

2.配置类扫描我们的后置处理器

package com.jsxs.config;
import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import com.jsxs.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 * bean 创建 -> 初始化 -> 销毁的过程
 * 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 * 1. init-method="" destroy-method=""
 * 2. 构造(对象创建)
 * 单实列: 在容器启动的时候创建对象
 * 多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */
@Configuration
@ComponentScan(value = "com.jsxs")  ⭐
public class MainConfigOfLifeCycle {
    // 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。
    @Bean(value = "car", destroyMethod = "destroy", initMethod = "init")
    public Car car() {
        return new Car();
    }
    @Bean
    public Car01 car01() {
        return new Car01();
    }
    @Bean
    public Dog dog(){
        return new Dog();
    }
}

3.测试类

package com.jsxs.Test;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

5.Spring底层对BeanPostProcessor的使用

(1). 【案例1】在实体类中获取ioc容器

1.实体类

package com.jsxs.bean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
 * @Author Jsxs
 * @Date 2023/8/16 15:37
 * @PackageName:com.jsxs.bean
 * @ClassName: Dog
 * @Description: TODO
 * @Version 1.0
 */
public class Dog implements ApplicationContextAware {  // ⭐继承这个IOC接口
    private ApplicationContext applicationContext;  // ⭐⭐
    public Dog() {
        System.out.println("dog constructor...");
    }
    @PostConstruct
    public void init() {
        System.out.println("dog 初始化中...");
    }
    @PreDestroy()
    public void destroy() {
        System.out.println("dog 销毁中...");
    }
    @Override // ⭐⭐⭐
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
    // ⭐⭐⭐⭐ 自己写一个获取IOC容器的方法 (便于调用)
    public ApplicationContext getApplicationContext(){
        return applicationContext;
    }
}

2.测试

package com.jsxs.Test;
import com.jsxs.bean.Dog;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        ConfigurableEnvironment environment1 = applicationContext.getEnvironment();
        System.out.println(environment1.getProperty("os.name"));
    // ⭐我们创建实列,并且  
        Dog dog = new Dog();
        ApplicationContext applicationContext1 = dog.getApplicationContext();
        for (String beanDefinitionName : applicationContext1.getBeanDefinitionNames()) {
            System.out.println("--->"+beanDefinitionName);
        }
    }
}

(三)、属性赋值相关的注解

/**
     * 使用@Value赋值
     *    1、基本数值
     *    2、可以些SpEL,#{}
     *    3、可以写${},取出配置文件中的值(即在运行环境变量中的值).
     *      通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
     *      Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
     */

1.@Value

(1).普通属性赋值 和 SPEL表达式赋值

1.需要注册的组件

package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Value;
/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {
  // ⭐ 
    @Value("李明")
    private String name;
    //  ⭐⭐ spel表达式
    @Value("#{20-2}")
    private Integer age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2.配置类

package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/17 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfPropertyValues
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MainConfigOfPropertyValues {
    @Bean
    public Person person() {
        return new Person();
    }
}

3.测试

package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MainConfigOfPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/17 9:07
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_PropertyValue
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_PropertyValue {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 2.通过组件名获取具体的组件信息
        Person person = (Person)annotationConfigApplicationContext.getBean("person");
        System.out.println(person);
    }
}

2. @PropertySource 加载外部配置文件

(1).使用配置文件的方式加载外部文件

1.beans.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!--     1.包自动扫描: 凡是带有 @Controller @Service @Repository @Component     -->
    <context:component-scan base-package="com.jsxs"/>
    <!--    2.从外部环境中获取值 ⭐-->
    <context:property-placeholder location="classpath:person.properties"/>
    <!--   3. 通过Bean的方式进行我们的组件注入的操作  并设置作用域为多实例 -->
    <bean id="person" class="com.jsxs.bean.Person" scope="prototype">
    <!--    4.从外部环境中获取值使用EL表达式 ⭐⭐-->
        <property name="name" value="${person.name}"/>
        <property name="age" value="19"/>
    </bean>
</beans>

2.resource/beans.xml

person.name=李明

3.Person.java 实体类

package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Value;
/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {
    /**
     *  1.基本数值
     *  2. 可以写Spel表达式,#{}
     *  3.可以写${},取出配置文件中的值(即在运行环境中的值)
     *  通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
     *  Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
     */
  //  ⭐⭐ 假如说这里加了@Value("${})注解也不会生效
    private String name;
    @Value("#{20-2}")
    private Integer age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

4.测试的操作

package com.jsxs.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/17 10:15
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_PropertyValue_anno
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_PropertyValue_XML {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(applicationContext.getBean("person"));
    }
}

结果:我们取到了我们外部的文件,但是因为是中文,所以出现中文乱码的操作

(2).使用注解的方式 加载外部文件

1.Person.java

package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Value;
/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {
    /**
     *  1.基本数值
     *  2. 可以写Spel表达式,#{}
     *  3.可以写${},取出配置文件中的值(即在运行环境中的值)
     *  通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
     *  Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
     */
  // ⭐⭐
    @Value("${person.name}")
    private String name;
    @Value("#{20-2}")
    private Integer age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2.配置文件 person.properties

person.name=asd

3.配置类

package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
 * @Author Jsxs
 * @Date 2023/8/17 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfPropertyValues
 * @Description: TODO
 * @Version 1.0
 */
 // ⭐⭐ 配置文件不写了,但是我们需要在配置类上添加这个注解用来指定我们去哪个配置文件中进行获取数据
@PropertySource(value = {"classpath:person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
    @Bean
    public Person person() {
        return new Person();
    }
}

4.测试类

package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MainConfigOfPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/17 9:07
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_PropertyValue
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_PropertyValue {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 2.通过组件名获取具体的组件信息
        Person person = (Person)annotationConfigApplicationContext.getBean("person");
        System.out.println(person);
    }
}


相关文章
|
1月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
50 0
|
2月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
133 3
|
18天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
38 2
|
23天前
|
前端开发 Java Spring
Spring MVC核心:深入理解@RequestMapping注解
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的核心,它将HTTP请求映射到控制器的处理方法上。本文将深入探讨`@RequestMapping`注解的各个方面,包括其注解的使用方法、如何与Spring MVC的其他组件协同工作,以及在实际开发中的应用案例。
37 4
|
1月前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
62 4
SpringBoot必须掌握的常用注解!
|
23天前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
69 2
|
23天前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
40 2
|
27天前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
32 2
|
27天前
|
JSON Java 数据格式
springboot常用注解
@RestController :修饰类,该控制器会返回Json数据 @RequestMapping(“/path”) :修饰类,该控制器的请求路径 @Autowired : 修饰属性,按照类型进行依赖注入 @PathVariable : 修饰参数,将路径值映射到参数上 @ResponseBody :修饰方法,该方法会返回Json数据 @RequestBody(需要使用Post提交方式) :修饰参数,将Json数据封装到对应参数中 @Controller@Service@Compont: 将类注册到ioc容器
|
28天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
38 2