第六次总结

自动装配

1. XML配置中的Bean自动装配

Spring IOC容器可以自动装配Bean.需要做的仅仅是在<bean>autowire属性中指定自动装配的模式

自动装配模式:

  • byType(根据类型自动装配):若IOC中有多个与目标Bean类型一致的Bean.在这种情况下Spring无法判断那个Bean最适合该属性,因此无法执行自动装配

  • byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同

  • constructor(通过构造器自动装配):当Bean中存在多个构造器时,此种自动装配方式将会很复杂.不推荐使用

    代码示例:

    Person.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
    package autowire;/*
    * @Author Sheng WenZeng
    * @Date 2019/8/10 23:04
    * @Version 1.0
    */


    /**
    * @author Sheng Wenzeng
    * @ClassName person
    * @Description TODO
    * @Date 2019/8/10 23:04
    * @Version 1.0
    */
    public class person {
    private String name;
    private Address address;
    private Car car;

    @Override
    public String toString() {
    return "person{" +
    "name='" + name + '\'' +
    ", address=" + address +
    ", car=" + car +
    '}';
    }

    public void setName(String name) {
    this.name = name;
    }

    public void setAddress(Address address) {
    this.address = address;
    }

    public void setCar(Car car) {
    this.car = car;
    }
    }

    Address.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
    package autowire;/*
    * @Author Sheng WenZeng
    * @Date 2019/8/10 23:05
    * @Version 1.0
    */

    /**
    * @author Sheng Wenzeng
    * @ClassName Address
    * @Description TODO
    * @Date 2019/8/10 23:05
    * @Version 1.0
    */
    class Address {
    private String city;
    private String street;

    @Override
    public String toString() {
    return "Address{" +
    "city='" + city + '\'' +
    ", street='" + street + '\'' +
    '}';
    }

    public void setCity(String city) {
    this.city = city;
    }

    public void setStreet(String street) {
    this.street = street;
    }
    }

    Car.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
    package autowire;/*
    * @Author Sheng WenZeng
    * @Date 2019/8/10 23:05
    * @Version 1.0
    */

    /**
    * @author Sheng Wenzeng
    * @ClassName Car
    * @Description TODO
    * @Date 2019/8/10 23:05
    * @Version 1.0
    */
    public class Car {
    private String brand;
    private double price;

    @Override
    public String toString() {
    return "Car{" +
    "brand='" + brand + '\'' +
    ", price=" + price +
    '}';
    }

    public void setBrand(String brand) {
    this.brand = brand;
    }

    public void setPrice(double price) {
    this.price = price;
    }
    }

    Main.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package autowire;/*
    * @Author Sheng WenZeng
    * @Date 2019/8/10 23:07
    * @Version 1.0
    */

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    /**
    * @author Sheng Wenzeng
    * @ClassName Main
    * @Description TODO
    * @Date 2019/8/10 23:07
    * @Version 1.0
    */
    public class Main {
    public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("autowire/autowire.xml");
    person person = (person) applicationContext.getBean("person");
    System.out.println(person.toString());
    }
    }

    autowire.xml

    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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="address" class="autowire.Address" p:city="HeFei" p:street="ShuangDun"/>
    <bean id="car" class="autowire.Car" p:brand="Audi" p:price="10000"/>
    <!--1. 常规装配方法-->
    <!-- <bean id="person" class="autowire.person" p:name="Tom" p:address-ref="address" p:car-ref="car"/>-->

    <!--2. 根据名字自动装配,要求前面的 bean 的 id 与要装配的类中的 setter 方法中的变量名称相同,若有匹配的则自送装配,没有则为空-->
    <!-- <bean id="person" class="autowire.person" p:name="Tom" autowire="byName"/>-->

    <!--3. 根据类型自动装配,如果IOC容器中有一个以上的类型匹配的 bean 则抛异常-->
    <bean id="person" class="autowire.person" p:name="Tom" autowire="byType"/>

    </beans>

    三种方式输出结果都是

    1
    person{name='Tom', address=Address{city='HeFei', street='ShuangDun'}, car=Car{brand='Audi', price=10000.0}}

2. 自动装配的缺点

  • 在Bean配置文件中设置autowire属性进行自动装配将会匹配Bean的所有属性.然而若只希望装配个别属性时,autowire就不够灵活了
  • autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之
  • 一般情况下,在实际项目中很少使用自动装配功能.因为和自动装配带来的好处比起来,明确清晰的配置文档更有说服力一点

Bean之间的关系

继承&依赖

1. 继承

先看一个例子:

address.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/10 23:30
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Address
* @Description TODO
* @Date 2019/8/10 23:30
* @Version 1.0
*/
public class Address {
private String city;
private String street;

@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
", street='" + street + '\'' +
'}';
}

public void setCity(String city) {
this.city = city;
}

public void setStreet(String street) {
this.street = street;
}
}

Main.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/10 23:31
* @Version 1.0
*/

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/10 23:31
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Address address = (Address) applicationContext.getBean("address");
System.out.println(address);
Address address_1 = (Address) applicationContext.getBean("address_1");
System.out.println(address_1);
}
}

applicationContext.xml

1
2
3
4
5
6
7
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/>
<bean id="address_1" class="relation.Address" p:city="HeFei" p:street="NanJingLu"/>
</beans>

运行结果为

1
2
Address{city='Beijing', street='NanJingLu'}
Address{city='HeFei', street='NanJingLu'}

可以发现其中配置的两个bean基本相同,因此第二个bean可以继承第一个bean,将applicationContext.xml修改为以下内容:

1
2
3
4
5
6
7
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/>
<bean id="address_1" parent="address" p:city="HeFei"/>
</beans>

结果相同

  • Spring允许继承Bean的配置,被继承的Bean成为父Bean.继承这个Bean的Bean成为子Bean
  • 子Bean从父Bean中继承配置,包括Bean的属性配置
  • 子Bean可以覆盖父Bean继承来的配置
  • 父Bean可以作为配置模板,也可以作为Bean实例.若只想把父Bean作为模板,可以设置<bean>的abstract属性为true,这样Sprint将不会实例化这个Bean
  • 并不是<bean>中所有属性都会被继承,比如:autowire,abstract等
  • 也可以忽略父Bean的class属性,让子Bean制定自己的类,而共享相同的属性配置.但此时abstract必须设置为true

2. 依赖

Spring允许用户通过depend-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好

如果前置依赖于多个Bean,则可以通过逗号空格的方式配置Bean的名称

例:

Person.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 0:03
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Person
* @Description TODO
* @Date 2019/8/11 0:03
* @Version 1.0
*/
public class Person {
private String name;
private Address address;
private Car car;

@Override
public String toString() {
return "person{" +
"name='" + name + '\'' +
", address=" + address +
", car=" + car +
'}';
}

public void setCar(Car car) {
this.car = car;
}

public void setName(String name) {
this.name = name;
}

public void setAddress(Address address) {
this.address = address;
}
}

Address.java同上

Car.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 0:09
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/11 0:09
* @Version 1.0
*/
public class Car {
private String brand;
private int speed;
private double price;

@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", speed=" + speed +
", price=" + price +
'}';
}

public void setBrand(String brand) {
this.brand = brand;
}

public void setSpeed(int speed) {
this.speed = speed;
}

public void setPrice(double price) {
this.price = price;
}
}

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/10 23:31
* @Version 1.0
*/

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/10 23:31
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}

applicationContext.xml

1
2
3
4
5
6
7
8
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/>
<bean id="address_1" parent="address" p:city="HeFei"/>
<bean id="person" class="relation.person" p:name="Tom" p:address-ref="address"/>
</beans>

输出:

1
person{name='Tom', address=Address{city='Beijing', street='NanJingLu'}, car=null}

如果要求person这个Bean一定要绑定一个Car,即person依赖于Car:

1
2
3
4
5
6
7
8
9
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/>
<bean id="address_1" parent="address" p:city="HeFei"/>
<bean id="car" class="relation.Car" p:brand="Audi" p:price="100000" p:speed="200"/>
<bean id="person" class="relation.Person" p:name="Tom" p:address-ref="address" depends-on="car"/>
</beans>

运行结果和之前仍然相同,但是已经这个id为car的Bean已经在person实例化之前被实例化了,只是car不属于person,所以person的car仍然为null

Bean的作用域

通过在<bean>标签中设置scope属性来指定作用域

  • singleton:默认的.容器初始时创建Bean实例.在整个容器的生命周期内只创建这一个Bean
  • prototype:容器初始化时不创建Bean实例.每次请求时创建一个新的实例

1. singleton

Address.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/10 23:30
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Address
* @Description TODO
* @Date 2019/8/10 23:30
* @Version 1.0
*/
public class Address {
private String city;
private String street;

public Address() {
System.out.println("Address' construction...");
}

@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
", street='" + street + '\'' +
'}';
}

public void setCity(String city) {
this.city = city;
}

public void setStreet(String street) {
this.street = street;
}
}

Main.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/10 23:31
* @Version 1.0
*/

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/10 23:31
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Address address = (Address) applicationContext.getBean("address");
Address address_1 = (Address) applicationContext.getBean("address");
System.out.println(address == address_1);
}
}

applicationContext.xml

1
2
3
4
5
6
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean scope="singleton" id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/>
</beans>

输出结果为:

1
2
Address' construction...
true

可见只是在容器初始化时创建了一次Bean,而后获取的Bean都是同一个对象

2. prototype

将上面的xml文件修改如下:

1
2
3
4
5
6
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean scope="prototype" id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/>
</beans>

而后运行,结果为:

1
2
3
Address' construction...
Address' construction...
false

可见容器初始化时没有新建Bean对象,而是每次请求时创建一个新的Bean对象

使用外部属性文件

在配置文件中配置Bean时,有时需要在Bean的配置中混入系统部署的细节信息(例如文件路径,数据源配置信息等).而这些部署细节实际上需要和Bean配置相分离

Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中.可以在Bean配置文件中使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件中嘉爱属性,并使用这些属性来替换变量

Spring还允许在属性文件中使用${propName},以实现属性之间的相互引用

正常获取数据库连接的配置如下:

pom.xml引入c3p0和MySQL驱动:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"/>
<property name="password" value="@SWZDL231100"/>
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/wechat?useUnicode=true&amp;characterEncoding=UTF-8&amp;useJDBCCompliantTimezoneShift=true&amp;useLegacyDatetimeCode=false&amp;serverTimezone=UTC"/>
</bean>

</beans>

Main.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
package relation;/*
* @Author Sheng WenZeng
* @Date 2019/8/10 23:31
* @Version 1.0
*/

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/10 23:31
* @Version 1.0
*/
public class Main {
public static void main(String[] args) throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}

运行结果为

1
com.mchange.v2.c3p0.impl.NewProxyConnection@27c6e487 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@49070868]

表示连接成功

但是此时数据库密码等都在applicationContext.xml中,不方便修改,可以将这些配置放在外部的配置文件中

新建配置文件名为DataSource.properties

1
2
3
4
user=root
password=@SWZDL231100
driverClass=com.mysql.cj.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/wechat?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

修改applicationContext.xml为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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="relation/DataSource.properties"/>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="driverClass" value="${driverClass}"/>
<property name="jdbcUrl"
value="${jdbcUrl}"/>
</bean>

</beans>

运行结果相同

SpEL

SpEL:Spring表达式语言,是一个支持运行时查询和操作对象图的强大表达式语言

语法类似于EL:SpEL使用#{...}作为定界符,所有在大括号中的字符都被认为是SpEL

SpEL为Bean的属性进行动态赋值提供了便利

通过SpEL可以实现:

  • 通过Bean的id对Bean进行引用
  • 调用方法以及引用对象中的属性
  • 计算表达式的值
  • 正则表达式的匹配

SpEL字面量(意义不大):

  • 整数:<property name = "count" value="#{5}"/>
  • 小数:<property name = "frequency" value="#{89.7}"/>
  • 科学计数法:<property name = "capacity" value="#{1e4}"/>
  • String可以使用单引号或者双引号作为字符串的定界符号:<property name = "name" value="#{'Chuck'}"/>或者:<property name = "name" value='#{"Chuck"}'/>
  • Boolean:<property name="enabled" value="#{false}"/>

引用Bean、属性和方法

  • 引用其他对象
  • 引用其他对象的属性
  • 调用其他方法,还可以链式操作

支持的运算符号

  • 算数运算符:+,-,*,/,%,^
  • 加号可拼接字符串
  • 比较运算符:<,>,==,<=,>=,lt,gt,eg,le,ge
  • 逻辑运算符:and,or,not
  • if-else运算符:?:(tenmary),?:(Elvis)
  • if-else的变体
  • 正则表达式:matches
  • 调用静态方法或静态属性:通过T()调用一个类的静态方法,他将返回一个Class Object,然后再调用相应的方法或属性

Address.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
package spel;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 8:46
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Address
* @Description TODO
* @Date 2019/8/11 8:46
* @Version 1.0
*/
public class Address {
private String city;
private String street;

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getStreet() {
return street;
}

public void setStreet(String street) {
this.street = street;
}

@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
", street='" + street + '\'' +
'}';
}
}

Car.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
46
47
48
49
50
51
package spel;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 8:44
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/11 8:44
* @Version 1.0
*/
public class Car {
private double price;
private String brand;
private int typePerimeter;

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public int getTypePerimeter() {
return typePerimeter;
}

public void setTypePerimeter(int typePerimeter) {
this.typePerimeter = typePerimeter;
}

@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
", typePerimeter=" + typePerimeter +
'}';
}
}

Person.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
package spel;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 8:44
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Person
* @Description TODO
* @Date 2019/8/11 8:44
* @Version 1.0
*/
public class Person {
private String name;
private Car car;
private String city;
private String info;

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", car=" + car +
", city='" + city + '\'' +
", info='" + info + '\'' +
'}';
}

public void setName(String name) {
this.name = name;
}

public void setCar(Car car) {
this.car = car;
}

public void setCity(String city) {
this.city = city;
}

public void setInfo(String info) {
this.info = info;
}
}

Main.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
package spel;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 8:49
* @Version 1.0
*/

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/11 8:49
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spel/spel.xml");
Car car = (Car) applicationContext.getBean("car_1");
System.out.println(car);

Address address = (Address) applicationContext.getBean("address");
System.out.println(address);

Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}

spel.xml

1
2
3
4
5
6
7
8
9
10
11
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用spel表达式引用类中的静态方法-->
<bean id="car_1" class="spel.Car" p:brand="Audi" p:price="300000" p:typePerimeter="#{T(Math).PI*80}"/>
<bean id="address" class="spel.Address" p:city="HeFei" p:street="ShuangDun"/>
<!--引用其他Bean中的属性:address.city; 使用if-else语句:car_1.price>10000? '金领':'白领'-->
<bean id="person" class="spel.Person" p:car="#{car_1}" p:city="#{address.city}" p:name="Sheng"
p:info="#{car_1.price>10000? '金领':'白领'}"/>
</beans>

运行结果:

1
2
3
Car{brand='Audi', price=300000.0, typePerimeter=251}
Address{city='HeFei', street='ShuangDun'}
Person{name='Sheng', car=Car{brand='Audi', price=300000.0, typePerimeter=251}, city='HeFei', info='金领'}

注意:引用其他Bean的属性时,需要被引用的Bean的类中有getter方法或者要引用的属性是public的

Bean的生命周期

1. IOC容器中Bean的生命周期方法

SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean的生命周期的特定点执行定制的任务

1.1 SpringIOC容器对Bean的生命周期进行管理的过程

  • 通过构造器或工厂方法创建Bean实例
  • 为Bean的属性设置值和对其他Bean的引用
  • 调用Bean的初始化方法
  • Bean可以使用了
  • 当容器关闭时,调用Bean的销毁方法

在Bean的声明里设置init-methoddestroy-method属性,为Bean指定初始化和销毁方法

通过实例来说明生命周期:

Car.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
package cycle;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 17:53
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/11 17:53
* @Version 1.0
*/
public class Car {
private String brand;

public Car() {
System.out.println("Car's constructor..");
}

@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
'}';
}

public void setBrand(String brand) {
System.out.println("setBrand...");
this.brand = brand;
}


public void init() {
System.out.println("init...");
}


public void destroy() {
System.out.println("destroy...");
}
}

Main.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
package cycle;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 17:57
* @Version 1.0
*/

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/11 17:57
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("cycle/cycle.xml");
Car car = (Car) applicationContext.getBean("car");
System.out.println(car);
applicationContext.close();

}
}

cycle.xml

1
2
3
4
5
6
7
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="car" class="cycle.Car" init-method="init" destroy-method="destroy" p:brand="Audi"/>
</beans>

运行结果为:

1
2
3
4
5
Car's constructor..
setBrand...
init...
Car{brand='Audi'}
destroy...

2. 创建Bean后置处理器

Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理

Bean后置处理器对IOC容器中的所有Bean实例逐一处理,而非单一实例.其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性

对Bean后置处理器而言,需要实现(org.springframework.bean.factory.comfig)

BeanPostProcessor接口,在初始化方法被调用前后,Spring将把每个Bean实例分别传递给上述接口的以上两个方法:

  • 通过构造器或工厂方法创建Bean实例
  • 为Bean的属性设置值和对其他Bean的引用
  • 调用Bean的初始化方法
  • Bean可以使用了
  • 当容器关闭时,调用Bean的销毁方法

通过实例来说明Bean后置处理器

Car.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
package cycle;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 17:53
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/11 17:53
* @Version 1.0
*/
public class Car {
private String brand;

public Car() {
System.out.println("Car's constructor..");
}

@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
'}';
}

public void setBrand(String brand) {
System.out.println("setBrand...");
this.brand = brand;
}


public void init() {
System.out.println("init...");
}


public void destroy() {
System.out.println("destroy...");
}
}

PosrProcesser.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
package cycle;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 20:58
* @Version 1.0
*/

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
* @author Sheng Wenzeng
* @ClassName PostProcessor
* @Description TODO
* @Date 2019/8/11 20:58
* @Version 1.0
*/
public class PostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization\t" + bean + "\t" + beanName);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization\t" + bean + "\t" + beanName);
return bean;
}
}

Main.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
package cycle;/*
* @Author Sheng WenZeng
* @Date 2019/8/11 17:57
* @Version 1.0
*/

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/11 17:57
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("cycle/cycle.xml");
Car car = (Car) applicationContext.getBean("car");
System.out.println(car);
applicationContext.close();

}
}

cycle.xml

1
2
3
4
5
6
7
8
9
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="car" class="cycle.Car" init-method="init" destroy-method="destroy" p:brand="Audi"/>

<bean class="cycle.PostProcessor"/>
</beans>

运行结果为:

1
2
3
4
5
6
7
Car's constructor..
setBrand...
postProcessBeforeInitialization Car{brand='Audi'} car
init...
postProcessBeforeInitialization Car{brand='Audi'} car
Car{brand='Audi'}
destroy...

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×