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


相关文章
|
17天前
|
XML Java 数据格式
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
19 1
|
17天前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
25 0
|
13天前
|
XML Java 数据库连接
Spring6(二):IoC容器(2)
Spring6(二):IoC容器
17 2
|
13天前
|
XML Java 数据格式
Spring6(二):IoC容器(3)
Spring6(二):IoC容器(3)
14 1
|
13天前
|
XML Java 数据格式
Spring6(二):IoC容器(1)
Spring6(二):IoC容器(1)
21 1
|
14天前
|
XML Java 数据格式
Spring的注解
Spring框架注解简化了Java应用开发,通过元数据替代XML配置。`@Component`、`@Controller`、`@Service`、`@Repository`都是组件注解,用于标记不同层的类,如`@Controller`用于控制层,`@Service`业务层,`@Repository`数据访问层。它们均会被组件扫描加入IOC容器,`@Component`是通用形式。通过`@ComponentScan`可以配置扫描规则,包括排除和包含特定类型的组件。`@Autowired`自动装配依赖,`@Value`能从属性文件读取值注入字段。`
|
3天前
|
XML Java 关系型数据库
面试一口气说出Spring的声明式事务@Transactional注解的6种失效场景
面试一口气说出Spring的声明式事务@Transactional注解的6种失效场景
|
3天前
|
Java 微服务 Spring
【spring cloud】注解@SpringCloudApplication和@SpringBootApplication的区别
【spring cloud】注解@SpringCloudApplication和@SpringBootApplication的区别
|
11天前
|
Java 测试技术 数据安全/隐私保护
Spring Boot中的自定义注解应用
Spring Boot中的自定义注解应用
|
12天前
|
容器
springboot-自定义注解拦截ip aop和ioc
springboot-自定义注解拦截ip aop和ioc