spring学习

原则

  1. 开闭原则(OCP)
    扩展新功能时,旧功能不需要更改。

  2. 依赖倒置原则(DIP)
    上面依赖下面,上面一改动,下面程序会受到牵连。
    面向接口、抽象编程,不要面向具体编程。(不喜欢 new)
    降低程序耦合度,提升扩展力。

  • 解决措施
    1、控制反转 IoC
    反转:
    (1)不采用硬编程来 new 对象
    (2)不采用硬编程来维护对象之间的关系
    实现方式:
    (1)依赖注入 DI
    set 注入(set 函数赋值)
    构造方法注入(构造函数赋值)
    2、Spring 框架

spring 程序

构造

  1. 采取 maven 模式构造
  2. 在 pom.xml 导入相关配置
  3. 写入 Beans.xml 相关配置
  • Beans.xml 中配置 id 是唯一的

  • spring 实例化对象本质
    调用本地无参构造函数

  • 创建好的对象以键(id)值(bean 对象)对方式存入 map 中

  • 导入 Beans.xml 文件需要写完整路径(根路径是 resource)

  • Beans.xml 文件可以导入自定义类也可以导入内置类

  • spring 底层的 IoC 实习
    XML 解析 + 工厂模式 + 反射机制
    工厂模式:将对象的创建和使用进行分离

  • 解析配置文件的时候就创建了对象,不是在 getbean 才创建对象

启用 log4j2 日志框架

  1. 引入 log4j2 依赖
    pom.xml
1
2
3
4
5
6
7
8
9
10
11
<!--log4j2的依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
  1. 类的根路径下提供 log4j2.xml 配置文件
    log4j2.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>

<configuration>

<loggers>
<!--
level指定日志级别,从低到高的优先级:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
-->
<root level="DEBUG">
<appender-ref ref="spring6log"/>
</root>
</loggers>

<appenders>
<!--输出日志信息到控制台-->
<console name="spring6log" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
</console>
</appenders>

</configuration>
  1. 使用日志框架
1
2
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);
logger.info("我是一条日志消息");

依赖注入

  • set 注入
    基于 set 方法实现的,底层会通过反射机制调用属性对应的 set 方法然后给属性赋值。这种方式要求属性必须对外提供 set 方法。

  • 构造注入
    通过调用构造方法来给属性赋值

  1. 外部 Bean
    bean 定义到外面,在 property 标签中使用 ref 属性进行注入。
1
2
3
<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
<property name="userDao" ref="userDaoBean"/>
</bean>
  1. 内部 Bean
    在 bean 标签中嵌套 bean 标签
1
2
3
4
5
<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
<property name="userDao">
<bean class="com.powernode.spring6.dao.UserDao"/>
</property>
</bean>
  1. 简单类型注入
    简单类型包括:
    ● 基本数据类型
    ● 基本数据类型对应的包装类
    ● String 或其他的 CharSequence 子类
    ● Number 子类
    ● Date 子类
    ● Enum 子类
    ● URI
    ● URL
    ● Temporal 子类
    ● Locale
    ● Class
    ● 另外还包括以上简单值类型对应的数组类型

  2. 级联属性赋值

1
2
3
4
5
6
7
8
<bean id="student" class="com.powernode.spring6.beans.Student">
<property name="name" value="张三"/>

<!--要点1:以下两行配置的顺序不能颠倒-->
<property name="clazz" ref="clazzBean"/>
<!--要点2:clazz属性必须有getter方法-->
<property name="clazz.name" value="高三一班"/>
</bean>
  1. 注入数组
  • 数组中的元素是简单类型
1
2
3
4
5
6
7
8
9
<bean id="person" class="com.powernode.spring6.beans.Person">
<property name="favariteFoods">
<array>
<value>鸡排</value>
<value>汉堡</value>
<value>鹅肝</value>
</array>
</property>
</bean>
  • 数组中的元素是非简单类型:一个订单中包含多个商品
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="goods1" class="com.powernode.spring6.beans.Goods">
<property name="name" value="西瓜"/>
</bean>

<bean id="goods2" class="com.powernode.spring6.beans.Goods">
<property name="name" value="苹果"/>
</bean>

<bean id="order" class="com.powernode.spring6.beans.Order">
<property name="goods">
<array>
<!--这里使用ref标签即可-->
<ref bean="goods1"/>
<ref bean="goods2"/>
</array>
</property>
</bean>
  1. 注入 List 集合
    List 集合:有序可重复
    People.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class People {
// 一个人有多个名字
private List<String> names;

public void setNames(List<String> names) {
this.names = names;
}

@Override
public String toString() {
return "People{" +
"names=" + names +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
<bean id="peopleBean" class="com.powernode.spring6.beans.People">
<property name="names">
<list>
<value>铁锤</value>
<value>张三</value>
<value>张三</value>
<value>张三</value>
<value>狼</value>
</list>
</property>
</bean>
  1. 注入 Set 集合
    Set 集合:无序不可重复
    People.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class People {
// 一个人有多个电话
private Set<String> phones;

public void setPhones(Set<String> phones) {
this.phones = phones;
}

//......

@Override
public String toString() {
return "People{" +
"phones=" + phones +
", names=" + names +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<bean id="peopleBean" class="com.powernode.spring6.beans.People">
<property name="phones">
<set>
<!--非简单类型可以使用ref,简单类型使用value-->
<value>110</value>
<value>110</value>
<value>120</value>
<value>120</value>
<value>119</value>
<value>119</value>
</set>
</property>
</bean>
  1. 注入 Map 集合
    People.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class People {
// 一个人有多个住址
private Map<Integer, String> addrs;

public void setAddrs(Map<Integer, String> addrs) {
this.addrs = addrs;
}

//......

@Override
public String toString() {
return "People{" +
"addrs=" + addrs +
", phones=" + phones +
", names=" + names +
'}';
}

}
1
2
3
4
5
6
7
8
9
10
<bean id="peopleBean" class="com.powernode.spring6.beans.People">
<property name="addrs">
<map>
<!--如果key不是简单类型,使用 key-ref 属性-->
<!--如果value不是简单类型,使用 value-ref 属性-->
<entry key="1" value="北京大兴区"/>
<entry key="2" value="上海浦东区"/>
<entry key="3" value="深圳宝安区"/>
</map>
</property>
  1. 注入 Properties
    java.util.Properties 继承 java.util.Hashtable,所以 Properties 也是一个 Map 集合
    People.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class People {

private Properties properties;

public void setProperties(Properties properties) {
this.properties = properties;
}

//......

@Override
public String toString() {
return "People{" +
"properties=" + properties +
", addrs=" + addrs +
", phones=" + phones +
", names=" + names +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
<bean id="peopleBean" class="com.powernode.spring6.beans.People">
<property name="properties">
<props>
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/spring</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
  1. 注入 null 和空字符串
1
2
3
4
5
<bean id="vipBean" class="com.powernode.spring6.beans.Vip">
<property name="email">
<null/>
</property>
</bean>
1
2
3
4
5
6
7
8
<bean id="vipBean" class="com.powernode.spring6.beans.Vip">
<!--空串的第一种方式-->
<!--<property name="email" value=""/>-->
<!--空串的第二种方式-->
<property name="email">
<value/>
</property>
</bean>
  1. 注入的值中含有特殊符号
    XML 中有 5 个特殊字符,分别是:<、>、’、"、&
1
2
3
<bean id="mathBean" class="com.powernode.spring6.beans.Math">
<property name="result" value="2 &lt; 3"/>
</bean>
1
2
3
4
5
6
<bean id="mathBean" class="com.powernode.spring6.beans.Math">
<property name="result">
<!--只能使用value标签-->
<value><![CDATA[2 < 3]]></value>
</property>
</bean>
  1. p 命名空间注入
    在 XML 头部信息中添加 p 命名空间的配置信息:xmlns:p=“http://www.springframework.org/schema/p
    p 命名空间注入是基于 setter 方法的,所以需要对应的属性提供 setter 方法。
1
2
xmlns:p="http://www.springframework.org/schema/p"
<bean id="customerBean" class="com.powernode.spring6.beans.Customer" p:name="zhangsan" p:age="20"/>
  1. c 命名空间注入
    需要在 xml 配置文件头部添加信息:xmlns:c=“http://www.springframework.org/schema/c
    需要提供构造方法。
    c 命名空间是依靠构造方法的。
1
2
xmlns:c="http://www.springframework.org/schema/c"
<bean id="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:_0="2008" c:_1="8" c:_2="8"/>
  1. util 命名空间注入
    配置多个数据源且引用相同时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<util:properties id="prop">
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/spring</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</util:properties>

<bean id="dataSource1" class="com.powernode.spring6.beans.MyDataSource1">
<property name="properties" ref="prop"/>
</bean>

<bean id="dataSource2" class="com.powernode.spring6.beans.MyDataSource2">
<property name="properties" ref="prop"/>
</bean>
  1. 基于 XML 的名称自动装配
    UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
public class UserService {

private UserDao aaa;

// 这个set方法非常关键
public void setAaa(UserDao aaa) {
this.aaa = aaa;
}

public void save(){
aaa.insert();
}
}
1
2
3
<bean id="userService" class="com.powernode.spring6.service.UserService" autowire="byName"/>

<bean id="aaa" class="com.powernode.spring6.dao.UserDao"/>
  1. 基于 XML 的类型自动装配
    AccountService.java
1
2
3
4
5
6
7
8
9
10
11
public class AccountService {
private AccountDao accountDao;

public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

public void save(){
accountDao.insert();
}
}
1
2
3
4
<!--byType表示根据类型自动装配-->
<bean id="accountService" class="com.powernode.spring6.service.AccountService" autowire="byType"/>

<bean class="com.powernode.spring6.dao.AccountDao"/>

spring 引入外部属性配置文件

jdbc.properties

1
2
3
4
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

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

<bean id="dataSource" class="com.powernode.spring6.beans.MyDataSource">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>

工厂模式

简单工厂模式

  1. 简单工厂模式的优点:
  • 客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责 “消费”,工厂负责 “生产”。生产和消费分离。
  1. 简单工厂模式的缺点:
  • 缺点 1:工厂类集中了所有产品的创造逻辑,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,不能出问题,一旦出问题,整个系统瘫痪。
  • 缺点 2:不符合 OCP 开闭原则,在进行系统扩展时,需要修改工厂类。
  1. Spring 中的 BeanFactory 就使用了简单工厂模式。

  2. 简单工厂模式的角色包括三个:

  • 抽象产品 角色
  • 具体产品 角色
  • 工厂类 角色
  1. 抽象产品 角色
    Weapon.java
1
2
3
4
5
6
public abstract class Weapon {
/**
* 所有的武器都有攻击行为
*/
public abstract void attack();
}
  1. 具体产品 角色
    Tank.java
1
2
3
4
5
6
public class Tank extends Weapon{
@Override
public void attack() {
System.out.println("坦克开炮!");
}
}

Fighter.java

1
2
3
4
5
6
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机投下原子弹!");
}
}

Dagger.java

1
2
3
4
5
6
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍他丫的!");
}
}
  1. 工厂类 角色
    WeaponFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static Weapon get(String weaponType){
if (weaponType == null || weaponType.trim().length() == 0) {
return null;
}
Weapon weapon = null;
if ("TANK".equals(weaponType)) {
weapon = new Tank();
} else if ("FIGHTER".equals(weaponType)) {
weapon = new Fighter();
} else if ("DAGGER".equals(weaponType)) {
weapon = new Dagger();
} else {
throw new RuntimeException("不支持该武器!");
}
return weapon;
}
}
  1. 主程序
1
2
3
4
5
6
7
8
9
10
11
12
public class Client {
public static void main(String[] args) {
Weapon weapon1 = WeaponFactory.get("TANK");
weapon1.attack();

Weapon weapon2 = WeaponFactory.get("FIGHTER");
weapon2.attack();

Weapon weapon3 = WeaponFactory.get("DAGGER");
weapon3.attack();
}
}

工厂方法模式

  1. 工厂方法模式的角色包括:
  • 抽象工厂角色
  • 具体工厂角色
  • 抽象产品角色
  • 具体产品角色
  1. 如果想扩展一个新的产品,只要新增一个产品类,再新增一个该产品对应的工厂即可

  2. 工厂方法模式的优点:

  • 一个调用者想创建一个对象,只要知道其名称就可以了。
  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  • 屏蔽产品的具体实现,调用者只关心产品的接口。
  1. 工厂方法模式的缺点:
  • 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

抽象工厂模式

抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。

  1. 抽象工厂中包含 4 个角色:
  • 抽象工厂角色
  • 具体工厂角色
  • 抽象产品角色
  • 具体产品角色

Bean 的实例化方式

  1. 通常包括 4 种方式
  • 第一种:通过构造方法实例化
  • 第二种:通过简单工厂模式实例化
  • 第三种:通过 factory-bean 实例化
  • 第四种:通过 FactoryBean 接口实例化
  1. 通过构造方法实例化
  • User.java
1
2
3
4
5
public class User {
public User() {
System.out.println("User类的无参数构造方法执行。");
}
}
  • spring.xml
1
<bean id="userBean" class="com.powernode.spring6.bean.User"/>
  • 主程序
1
2
3
4
5
public void testConstructor(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean("userBean", User.class);
System.out.println(user);
}
  1. 通过简单工厂模式实例化
  • Vip.java
1
2
public class Vip {
}
  • VipFactory.java
1
2
3
4
5
public class VipFactory {
public static Vip get(){
return new Vip();
}
}
  • spring.xml
1
<bean id="vipBean" class="com.powernode.spring6.bean.VipFactory" factory-method="get"/>
  • 主程序
1
2
3
4
5
public void testSimpleFactory(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Vip vip = applicationContext.getBean("vipBean", Vip.class);
System.out.println(vip);
}
  1. 通过 factory-bean 实例化
    通过工厂方法模式进行实例化。
  • Order.java
1
2
public class Order {
}
  • OrderFactory.java
1
2
3
4
5
public class OrderFactory {
public Order get(){
return new Order();
}
}
  • spring.xml
1
2
<bean id="orderFactory" class="com.powernode.spring6.bean.OrderFactory"/>
<bean id="orderBean" factory-bean="orderFactory" factory-method="get"/>
  • 主程序
1
2
3
4
5
public void testSelfFactoryBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Order orderBean = applicationContext.getBean("orderBean", Order.class);
System.out.println(orderBean);
}
  1. 通过 FactoryBean 接口实例化
    主要是对上一种方法的改进。
    在 Spring 中,当你编写的类直接实现 FactoryBean 接口之后,factory-bean 不需要指定了,factory-method 也不需要指定了。
    factory-bean 会自动指向实现 FactoryBean 接口的类,factory-method 会自动指向 getObject () 方法。

FactoryBean 在 Spring 中是一个接口。被称为 “工厂 Bean”。“工厂 Bean” 是一种特殊的 Bean。所有的 “工厂 Bean” 都是用来协助 Spring 框架来创建其他 Bean 对象的。

  • person.java
1
2
public class Person {
}
  • FactoryBean 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class PersonFactoryBean implements FactoryBean<Person> {

@Override
public Person getObject() throws Exception {
return new Person();
}

@Override
public Class<?> getObjectType() {
return null;
}

@Override
public boolean isSingleton() {
// true表示单例
// false表示原型
return true;
}
}
  • spring.xml
1
<bean id="personBean" class="com.powernode.spring6.bean.PersonFactoryBean"/>
  • 主程序
1
2
3
4
5
6
7
8
public void testFactoryBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);

Person personBean2 = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean2);
}
  1. 注入自定义 Date
  • DateFactoryBean 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DateFactoryBean implements FactoryBean<Date> {

// 定义属性接收日期字符串
private String date;

// 通过构造方法给日期字符串属性赋值
public DateFactoryBean(String date) {
this.date = date;
}

@Override
public Date getObject() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(this.date);
}

@Override
public Class<?> getObjectType() {
return null;
}
}
  • spring.xml
1
2
3
4
5
6
7
<bean id="dateBean" class="com.powernode.spring6.bean.DateFactoryBean">
<constructor-arg name="date" value="1999-10-11"/>
</bean>

<bean id="studentBean" class="com.powernode.spring6.bean.Student">
<property name="birth" ref="dateBean"/>
</bean>
  • 主程序
1
2
3
4
5
public void testDate(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student studentBean = applicationContext.getBean("studentBean", Student.class);
System.out.println(studentBean);
}

Bean 的生命周期

5 步

  1. 步骤
  • 第一步:实例化 Bean
  • 第二步:Bean 属性赋值
  • 第三步:初始化 Bean
  • 第四步:使用 Bean
  • 第五步:销毁 Bean
  1. 举例
  • 第一:只有正常关闭 spring 容器,bean 的销毁方法才会被调用。

  • 第二:ClassPathXmlApplicationContext 类才有 close () 方法。

  • 第三:配置文件中的 init-method 指定初始化方法。destroy-method 指定销毁方法。

  • User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class User {
private String name;

public User() {
System.out.println("1.实例化Bean");
}

public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}

public void initBean(){
System.out.println("3.初始化Bean");
}

public void destroyBean(){
System.out.println("5.销毁Bean");
}

}
  • spring.xml
1
2
3
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="zhangsan"/>
</bean>
  • 主程序
1
2
3
4
5
6
7
8
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("4.使用Bean");
// 只有正常关闭spring容器才会执行销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}

7 步

如果你还想在初始化前和初始化后添加代码,可以加入 “Bean 后处理器”。

  1. 步骤
  • 第一步:实例化 Bean

  • 第二步:Bean 属性赋值

  • 第三步:Bean 后处理器 before 执行

  • 第四步:初始化 Bean

  • 第五步:Bean 后处理器 after 执行

  • 第六步:使用 Bean

  • 第七步:销毁 Bean

  • LogBeanPostProcessor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的before方法执行,即将开始初始化");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的after方法执行,已完成初始化");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
  • spring.xml
1
2
<!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
  • 主程序
1
2
3
4
5
6
7
8
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("4.使用Bean");
// 只有正常关闭spring容器才会执行销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}

10 步

  1. 步骤
  • 第一步:实例化 Bean
  • 第二步:Bean 属性赋值
  • 第三步:检测 Bean 是否实现了 Aware 的相关接口,并设置相关依赖
  • 第四步:Bean 后处理器 before 执行
  • 第五步:检测 Bean 是否实现了 InitialzingBean 接口,并调用接口方法
  • 第六步:初始化 Bean
  • 第七步:Bean 后处理器 after 执行
  • 第八步:使用 Bean
  • 第九步:检测 Bean 是否实现了 DisposableBean 接口,并调用接口方法
  • 第十步:销毁 Bean
  1. Aware 的相关接口
    Aware 相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
  • 当 Bean 实现了 BeanNameAware,Spring 会将 Bean 的名字传递给 Bean。
  • 当 Bean 实现了 BeanClassLoaderAware,Spring 会将加载该 Bean 的类加载器传递给 Bean。
  • 当 Bean 实现了 BeanFactoryAware,Spring 会将 Bean 工厂对象传递给 Bean。
  1. 试以上 10 步,可以让 User 类实现 5 个接口,并实现所有方法:
  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • InitializingBean
  • DisposableBean
  1. 举例
  • User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
private String name;

public User() {
System.out.println("1.实例化Bean");
}

public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}

public void initBean(){
System.out.println("6.初始化Bean");
}

public void destroyBean(){
System.out.println("10.销毁Bean");
}

@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("3.类加载器:" + classLoader);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3.Bean工厂:" + beanFactory);
}

@Override
public void setBeanName(String name) {
System.out.println("3.bean名字:" + name);
}

@Override
public void destroy() throws Exception {
System.out.println("9.DisposableBean destroy");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5.afterPropertiesSet执行");
}
}
  • LogBeanPostProcessor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("4.Bean后处理器的before方法执行,即将开始初始化");
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
  • spring.xml
1
2
<!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
  • 主程序
1
2
3
4
5
6
7
8
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("4.使用Bean");
// 只有正常关闭spring容器才会执行销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}

自己 new 的对象让 Spring 管理

  • User.java
1
2
public class User {
}
  • 主程序
1
2
3
4
5
6
7
8
9
10
11
12
13
public void testBeanRegister(){
// 自己new的对象
User user = new User();
System.out.println(user);

// 创建 默认可列表BeanFactory 对象
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 注册Bean
factory.registerSingleton("userBean", user);
// 从spring容器中获取bean
User userBean = factory.getBean("userBean", User.class);
System.out.println(userBean);
}

Bean 循环依赖

访问量 访客