Java | Spring框架学习笔记--(1)工厂

该笔记从孙哥的视频(链接)整理而来,如果有什么不当的地方欢迎指出!
另外推荐大佬整理的笔记:传送门

系列文章:
Java | Spring框架学习笔记–(1)工厂
Java | Spring框架学习笔记–(2)AOP
Java | Spring框架学习笔记–(3)持久层整合
Java | Spring框架学习笔记–(4)MVC框架整合
Java | Spring框架学习笔记–(5)注解编程

Spring笔记(1) 工厂

什么是Spring

Spring是⼀个轻量级JavaEE解决⽅案,整合众多优秀的设计模式

  • 轻量级:
  1. 对于运行环境是没有额外要求的。
    可以在开源的tomcat resion jetty里运行,也可以在收费的weblogic websphere里运行。
  2. 代码移植性高:不需要事先额外的接口。
  • JavaEE解决方案:

在这里插入图片描述

  • 整合设计模式(工厂、代理等)

设计模式

  1. ⼴义概念
    ⾯向对象设计中,解决特定问题的经典代码
  2. 狭义概念
    GOF4⼈帮定义的23种设计模式:⼯⼚、适配器、装饰器、⻔⾯、代理、模板…

工厂设计模式

  1. 概念:通过⼯⼚类,创建对象,不提倡通过直接new的方法的创建对象

     User user = new User();
     UserDAO userDAO = new UserDAOImpl();
    
  2. 好处:解耦合

    耦合:指定是代码间的强关联关系,⼀⽅的改变会影响到另⼀⽅
    问题:不利于代码维护
    简单:把接⼝的实现类,硬编码在程序中

    UserService userService = new UserServiceImpl();
    

比如说我们目前使用UserServiceImpl作为UserService的一个实现类,当突然有一天我们需要升级或者其他说明原因,需要把实现类改成UserServiceImpl2,就还需要再改动一次代码,就还需要重新编译一次。

public static void main(String[] args) {
    UserService userService = new UserServiceImpl();
    userService.login("abcabc","123456");
}

一个比较好的解决方法就是使用工厂来创建对象

public static void main(String[] args) {
    UserService userService = Factory.getUserService();
    userService.login("abcabc","123456");
}

总结:

Spring本质:⼯⼚ ApplicationContext (applicationContext.xml)

第一个Spring

环境搭建

jar包

在maven的中心仓库,搜索spring,导入相应的依赖,这里选择spring context在这里插入图片描述

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.0</version>
</dependency>

配置文件

配置文件放置的位置:任意位置
配置文件的命名:没有硬性要求,建议applicationContext.xml

以后使用Spring框架时,需要进行配置文件路径的设置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

核心API

ApplicationContext:Spring提供的一个工厂对象,用于对象的创建。好处:解耦合。

ApplicationContext是一个接口类型,屏蔽实现的差异。

在非web环境下,主要使用ClassPathXmlApplicationContext实现类,在web环境下主要使用XmlWebApplicationContext实现类

ApplicationContext工厂对象需要占用大量的内存(重量级),所以我们不会频繁地创建这个对象(一个应用智慧创建一个工厂对象),而且这个对象一定是线程安全的。

程序开发

  1. 新建一个类

  2. 在applicationContext.xml中引入

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--
            id:唯一
            class:全限定类名
        -->
        <bean id="person" class="com.prince.Person"></bean>
    </beans>
    
  3. Main

    public class TestPerson {
        @Test
        public void test(){
            //创建Spring的工厂对象,并且在构造方法中指定配置文件的位置
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
            //根据id创建对象
            Person person = (Person)applicationContext.getBean("person");
            //测试
            System.out.println(person);
        }
    }
    

细节分析

由Spring创建的对象,叫做Bean或者Component

常见方法
  1. 直接通过id值获得bean对象,但是需要强制转换

    Person person = (Person)applicationContext.getBean("person");
    
  2. 传入一个class字节码对象,就可以不用强制类型转换了

    Person person = applicationContext.getBean("person",Person.class);
    
  3. 甚至可以直接只传入一个class字节码对象,表示根据类型来获取值

    Person person = applicationContext.getBean(Person.class);
    

    注意:当Spring的容器中只存在一个Person对象时,才能够这样子获取,如果有多个,会报异常(他不知道你想要的是哪个)。

  4. 获取bean的所有id

    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    System.out.println(Arrays.toString(beanDefinitionNames));
    
  5. 获取指定类的所有id

    String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
    for (String s : beanNamesForType) {
        System.out.println(s);
    }
    
  6. 判断是否存在指定的id

    applicationContext.containsBeanDefinition("person");//当配置文件显式定义了id时,只判断id 不判断name  ,没有显式定义id时,也可以判断name
    applicationContext.containsBean("person");//id 和 name 都可以判断
    
配置文件
  1. 只配置class属性,不配置id属性

    <bean class="com.prince.Person"></bean>
    

    问:没有手动设置id值,他有没有id
    验证:

    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
    

    输出结果为:

    com.prince.Person#0
    

    可以看到,当不指定id值的时候,spring 默认会为我们提供一个id值
    如果这个bean只需要使用一次,那么久可以省略id值。如果会使用多次,或者需要被其他bean引用时,就必须要指定id属性!

  2. name属性:用于给bean定义别名(小名)

    相同点:在getBean()方法,可以同时传id和name来获取对象。(name可以取代id的作用)

    <bean name="p" class="com.prince.Person"></bean>
    
    Person p = applicationContext.getBean("p",Person.class);
    System.out.println(p);
    

    区别:

    1. 别名可以定义多个(用逗号分隔),但是ID只能定义一个

      <bean name="p1,p2,p3" class="com.prince.Person"></bean>
      
    2. 在XML中,id属性的命名要求:必须以字母开头,不能以特殊字符开头。name则没有要求。所以name属性会应用在特殊命名的场景下。
      但是xml发展到今天,id的限制已不存在。

    3. containsBeanDefinitioncontainsBean的区别。

Spring与日志框架

Spring与⽇志框架进⾏整合,⽇志框架就可以在控制台中,输出Spring框架运⾏过程中的⼀些重要的信息。
好处:便于了解Spring框架的运⾏过程,利于程序的调试

如何整合日志框架?

默认情况下:

​ Spring 1 2 3等早期版本都是使用commons-logging.jar
​ Spring 5.x默认整合的是 logback log4j2

如何整合log4j(我们不要log4j2)?

  1. 引入log4j的jar包

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>
    
  2. 创建log4j.properties

    log4j.rootLogger=debug,stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.out
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
    

之后就可以很清楚地看到Spring的运行情况:
在这里插入图片描述

注入

注入:通过Spring工厂及配置文件,为所创建的成员变量赋值。

平常的时候为成员变量赋值(使用代码的方式,存在耦合问题):

@Test
public void test4(){
    Person p = applicationContext.getBean("p",Person.class);
    p.setName("xiaoming");
    p.setAge(18);
    System.out.println(p);
}

使用Spring的配置文件来注入:

<bean name="p1" class="com.prince.Person">
    <property name="name">
    	<value>aaa</value>
    </property>
    <property name="age">
    	<value>18</value>
    </property>
</bean>
<bean name="p1" class="com.prince.Person">
    <property name="name" value="aaa"/>
    <property name="age" value="18" />
</bean>

好处:解耦合

Set注入

Spring调用Set方法,通过配置文件,为成员变量赋值。

String+8种基本类型

property标签里面嵌套value即可。

<property name="name">
    <value>aaa</value>
</property>
数组

property标签里面嵌套list,然后再在list里嵌套多个value即可。

<property name="emails">
    <list>
        <value>123456@qq.com</value>
        <value>123456@163.com</value>
        <value>123456@126.com</value>
        <value>123456@gmail.com</value>
    </list>
</property>
Set集合

property标签里面嵌套set,然后再在set里嵌套多个value即可。

<property name="tels">
    <set>
        <value>18888888888</value>
        <value>18888888889</value>
        <value>18888888890</value>
        <value>18888888890</value>
    </set>
</property>

细节:由于Set集合本身是无序的,所以最终输出的顺序不一定会和这个一样。由于Set是无重复的,即使加入了重复的元素,也会自动去重。

List集合

和数组一样,都是property里嵌套list

Map集合
<property name="map">
    <map>
        <entry key="k1" value="v1"/>
        <entry>
            <key><value>k2</value></key>
            <value>v2</value>
        </entry>
        <entry>
        	<key><ref bean=""></ref></key>
            <ref bean=""></ref>
        </entry>
    </map>
</property>

注意:key有专属的标签,写在key里面的内容就是key,因为第5行我的key是String类型,所以我在里面嵌套value标签,如果key是一个对象,那么key标签里面嵌套的是ref标签。
key外面的都是value。

Property
<property>
	<props>
    	<prop key="k1">v1</prop>
    </props>
</property>
用户自定义类型

第一种方式:直接在property里面加bean 标签即可,因为那个bean仅使用一次,所以不需要id属性

<bean id="userServer" class="com.prince.basic.UserServiceImpl">
    <property name="userDao">
        <bean class="com.prince.basic.UserDaoImpl"></bean>
    </property>
</bean>

第二种方式:

<bean id="userDao" class="com.prince.basic.UserDaoImpl"></bean>

<bean id="userServer" class="com.prince.basic.UserServiceImpl">
    <property name="userDao">
        <ref bean="userDao"></ref>
    </property>
</bean>
简化方法
  1. 基于属性简化

    <property name="name" value="aaa"/>
    <property name="userDao" ref="userDao">
    
  2. 基于p命名空间简化

    <bean name="p" class="com.prince.Person" p:name="bbb" p:age="180"></bean>
    <bean id="userServer" class="com.prince.basic.UserServiceImpl" p:userDao-ref="userDao"></bean>
    

    直接写在bean标签上,p是property的缩写。

构造注入

Spring调用构造方法来赋值。前提:提供有参构造方法。

  1. 必须提供有参构造方法。

    public class People {
        public String name;
        public int age;
    
        public People() {
        }
        
        public People(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
  2. 配置bean标签的时候,里面不再是property标签,而是constructor-arg

    <bean id="people" class="com.prince.People">
        <constructor-arg>
            <value>zhangsan</value>
        </constructor-arg>
        <constructor-arg>
            <value>18</value>
        </constructor-arg>
    </bean>
    

    这里需要注意的是,constructor-arg标签的个数,和顺序,必须要和构造方法里的保持一致!

注:当构造函数的参数个数不一样时,可以通过<constructor-arg>标签的个数进行区分。

当参数个数一样时,需要指定type属性,如果不指定,他将会随机选一个来注入。

<bean id="people1" class="com.prince.People">
    <constructor-arg type="int">
        <value>123</value>
    </constructor-arg>
</bean>

反转控制与依赖注入

反转控制

控制:对于成员变量赋值的控制权
反转控制:把对于成员变量赋值的控制权,从代码中转移到Spring工厂的配置文件中完成。
好处:解耦合
底层实现:工厂设计模式

在这里插入图片描述

依赖注入

注入:通过Spring的工厂及配置文件,为对象(bean,组件)的成员变量赋值。

依赖注⼊:当⼀个类需要另⼀个类时,就意味着依赖,⼀旦出现依赖,就可以把另⼀个类作为本类的成员变量,最终通过Spring配置⽂件进⾏注⼊(赋值)

在这里插入图片描述

复杂对象创建

简单对象:可以直接通过new的方式创建
复杂对象:不能通过new的方式创建,比如Connection、SqlSessionFactory

在这里插入图片描述

实现FactoryBean接口

在这里插入图片描述

开发步骤:

  1. 新建一个类,继承FactoryBean接口。使用FactoryBean接口的时候,要指定泛型。
public class ConnectionFactory implements FactoryBean<Connection> {

    /**
     * 创建复杂对象的过程放在这,Spring会拿它的返回值来当做要创建的对象。
     * @return 复杂对象
     * @throws Exception
     */
    @Override
    public Connection getObject() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection("jdbc:mysql:///mydata","root","root");
    }

    /**
     * 
     * @return 复杂对象的Class字节码文件
     */
    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }

    /**
     * 是否单例
     * @return true或者false
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}

  1. Spring配置文件的配置
    <!--错误认知:通过getBean获取conn,得到的是ConnectionFactory对象。
        其实,Spring会对者做特殊处理,如果class指定的是FactoryBean接口,那么通过getBean获取到的就是那个复杂对象。
    -->
    <bean id="conn" class="com.factorybean.ConnectionFactory"></bean>

​ 细节:如果就是想获取FactoryBean对象,而不是对应的复杂对象,可以在getBean里面的id前面加&

applicationContext.getBean("&conn");

依赖注入改造

Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection("jdbc:mysql:///mydata","root","root");

这四个参数对于Connection来说都是非常重要的,也就是依赖。

我们可以通过依赖注入的方式改造这个类:

public class ConnectionFactory1 implements FactoryBean<Connection> {

    public String driverName;
    public String url;
    public String username;
    public String password;
	//getter setter略

    @Override
    public Connection getObject() throws Exception {
        Class.forName(driverName);
        return DriverManager.getConnection(url,username,password);
    }
	//getObjectType isSingleton 略

}

配置文件中通过Set注入,好处:解耦合!!

<bean id="conn1" class="com.factorybean.ConnectionFactory1">
    <property name="driverName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///mydata"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

FactoryBean总结:FactoryBean是Spring中用于创建复杂对象的一种方式,后续讲Spring整合其他框架会大量使用这种模式!

实例工厂

为什么使用实例工厂?

  1. 避免Spring框架的侵入(FactoryBean是Spring框架提供的)
  2. 整合遗留系统

开发步骤:

  1. 创建一个工厂类,创建一个getInstance()或者getXxxx()方法来创建一个对象。

    /**
     * 使用实例工厂创建
     */
    public class ConnectionFactory2 {
        public Connection getConnection(){
            Connection conn = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                conn = DriverManager.getConnection("jdbc:mysql:///mydata","root","root");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
            }
            return conn;
        }
    }
    
  2. Spring配置文件,factory-bean填的是工厂类的bean,factory-method填的是工厂类创建工厂的方法。

    <!--实例工厂-->
    <bean id="connfactory" class="com.factorybean.ConnectionFactory2"></bean>
    <bean id="conn2" factory-bean="connfactory" factory-method="getConnection"></bean>
    

静态工厂

静态工厂和实例工厂的区别是:实例工厂的类的创建对象的方法不是静态的,而静态工厂的方法是静态的,所以使用静态工厂就省去了创建工厂类这一步。

<bean id="conn3" class="com.factorybean.ConnectionFactory3" factory-method="getConnection"></bean>

控制Spring工厂创建对象的次数

简单对象

添加一个scope属性即可

<bean id="account" scope="singleton|prototype" class="xxxx.Account"/>
sigleton:只会创建⼀次简单对象 默认值
prototype:每⼀次都会创建新的对象  

复杂对象

FactoryBean{
    isSingleton(){
        return true 只会创建⼀次
        return false 每⼀次都会创建新的
    }
}
如没有isSingleton⽅法 还是通过scope属性 进⾏对象创建次数的控制

对象的生命周期

生命周期:指的是一个对象创建、存活、消亡的一个完整过程

创建阶段

创建阶段:Spring工厂何时创建对象

  • scope="singleton" Spring工厂创建的同时,创建对象
  • scope="prototype" Spring工厂在获取对象的同时,创建对象

验证:xml文件里:

<bean id="pro" class="com.life.Product" scope="singleton"></bean>

效果:在执行完下面代码后,对象创建(可以看到控制台中输出了构造方法打印的文字)

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/life.xml");

scope="prototype"的对象,只有调用了getBean()方法之后才会创建对象。

如果,singleton的对象也想实现prototype的那种效果(只有调用了getBean()才会创建对象),可以加入懒加载属性lazy-init

<bean id="pro" class="com.life.Product" scope="singleton" lazy-init="true"></bean>

初始化阶段

Spring工厂在创建完对象后,会调用对象的初始化方法,完成对应的初始化操作。

初始化方法,由程序员根据需求来提供;初始化方法的调用,由Spring来完成。

实现初始化的方式
  • 实现InitializingBean接口,重写afterPropertiesSet()方法,在方法里面执行初始化语句。

    public class Product implements InitializingBean {
        public Product() {
            System.out.println("Product对象已创建");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("初始化");
        }
    }
    
    
    <bean id="pro" class="com.life.Product" scope="singleton"></bean>
    

    执行代码,输出:
    在这里插入图片描述

  • 类中提供一个普通方法,然后再在配置文件中指定init-method属性
    我这里配置的初始化方法是init()

    <bean id="pro1" class="com.life.Product1" scope="singleton" init-method="init"></bean>
    

细节:

  1. 如果一个对象实现InitializingBean接口的同时,又提供普通的初始化方法,那么两个初始化方法都会执行。
  2. 注入在初始化之前执行

销毁阶段

Spring销毁对象前,会调用对象的销毁方法,完成销毁操作。

Spring什么时候销毁对象? 答:工厂关闭的时候

((ClassPathXmlApplicationContext)applicationContext).close();
实现销毁的方式
  • 实现DisposableBean接口

    public class Product2 implements DisposableBean {
        public Product2() {
            System.out.println("Product对象已创建");
        }
        
    
        @Override
        public void destroy() throws Exception {
            System.out.println("销毁方法");
        }
    }
    
    
  • 自定义销毁方法

    <bean id="pro3" class="com.life.Product3" scope="singleton" destroy-method="myDestroy"></bean>
    

细节:

  1. 销毁方法只使用于scope="singleton"
  2. 如果两种销毁方法都存在,那么两种方法都执行

在这里插入图片描述

配置文件参数化

把Spring配置文件中需要经常修改的字符串信息,转移到一个更小的配置文件中。

1. Spring的配置⽂件中存在需要经常修改的字符串?
	存在 以数据库连接相关的参数 代表
2. 经常变化字符串,在Spring的配置⽂件中,直接修改
	不利于项⽬维护(修改)
3. 转移到⼀个⼩的配置⽂件(.properties)
	利于维护(修改)

比如一个druid的链接池:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///mydata"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

原来是那些value都整合在一个配置文件中,可以通过下面的方法来把那些value分离出去

dp.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///mydata
username=root
password=root

applicationContext.xml

<context:property-placeholder location="dp.properties"></context:property-placeholder>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${driverClassName}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</bean>

类型转换器

类型转换器

作⽤: Spring通过类型转换器把配置⽂件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进⽽完成了注⼊

在这里插入图片描述

自定义类型转换器

当Spring内部没有提供特定的类型转换器,而程序员在应用的过程中还需要使用,那么就需要自定义类型转换器
如:日期格式

<bean id="person" class="com.prince.Person">
    <property name="id" value="111" />
    <property name="birthday" value="2020-11-11"/>
</bean>

运行的时候直接报错:

在这里插入图片描述

原因:缺少转换器,没法把字符串"2020-11-11"转成Date对象
解决方法:添加自定义类型转换器(实现Converter接口,然后在Spring配置文件中注册)

  1. 新建一个类,实现Converter接口
    可以发现Converter是一个泛型,Converter<S,T>中,S表示源类型,T表示要转换的类型。
    踩坑:Converter是org.springframework.core.convert.converter.Converter,不要导错包。

    public class MyConvert implements Converter<String, Date> {
    
        @Override
        public Date convert(String s) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            try {
                return sdf.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }
    
  2. 在Spring配置文件中注册,让Spring知道有这个类

    <!--第一步:创建这个转换器类的对象(最基本)-->
    <bean id="myConvert" class="com.prince.MyConvert" />
    <!--第二步:创建ConversionServiceFactoryBean对象,注入那个转换器,用于告诉Spring-->
    <!--踩坑:id一定是conversionService,否则不起作用-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <!--观察源码发现,converters是一个Set集合-->
            <set>
                <ref bean="myConvert" />
            </set>
        </property>
    </bean>
    

细节

  1. 自定义类型转换器的"yyyy-MM-dd"可以用依赖注入。

    public class MyConvert implements Converter<String, Date> {
        public String pattern;
    
        public String getPattern() {
            return pattern;
        }
    
        public void setPattern(String pattern) {
            this.pattern = pattern;
        }
    
        @Override
        public Date convert(String s) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            try {
                return sdf.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }
    
    <bean id="myConvert" class="com.prince.MyConvert" >
        <property name="pattern" value="yyyy-MM-dd"/>
    </bean>
    
  2. ConversionServiceFactoryBean的id值必须是conversionService

  3. Spring内置的String–>Date转换器只支持yyyy/MM/dd

后置处理Bean

BeanPostProcessor

BeanPostProcessor 作⽤:对Spring⼯⼚所创建的对象,进⾏再加⼯。

底层实现:

在这里插入图片描述

程序员实现BeanPostProcessor规定接⼝中的⽅法:

    Object postProcessBeforeInitiallization(Object bean String beanName)
    作⽤: Spring创建完对象,并进⾏注⼊后,可以运⾏Before⽅法进⾏加⼯
    获得Spring创建好的对象 :通过⽅法的参数
    最终通过返回值交给Spring框架
    
    Object postProcessAfterInitiallization(Object bean String beanName)
    作⽤: Spring执⾏完对象的初始化操作后,可以运⾏After⽅法进⾏加⼯
    获得Spring创建好的对象 :通过⽅法的参数
    最终通过返回值交给Spring框架

开发步骤

  1. 新建一个类,实现BeanPostProcessor接口

    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            Person person = (Person)bean;
            person.setId(9999);
            return person;
        }
    }
    
    
  2. 在Spring配置文件中配置(只需要把这个对象创建出来就行了)

    <bean id="beanPostProcessor" class="com.prince.MyBeanPostProcessor"></bean>
    

注意:

  1. 不是Person类实现BeanPostProcessor接口,而是重新写一个类来实现这个接口

  2. 一旦配置了这个BeanPostProcessor,那么这个工厂里创建的所有bean都会经过这个处理器,所以为了避免类型转换异常,需要加一个判断:

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Person){
            Person person = (Person)bean;
            person.setId(9999);
        }
        return bean;
    }
    
  3. 在Spring配置文件中配置(只需要把这个对象创建出来就行了)

    <bean id="beanPostProcessor" class="com.prince.MyBeanPostProcessor"></bean>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值