第七次总结

本周事情比较多(明天去学校参加活动),因此学的知识比较少

通过工厂方法配置Bean

Bean的配置方式,除了全类名(反射机制)之外,还可以通过**工厂方法(静态工厂方法&实例工厂方法)**以及FactoryBean的方式来配置

1. 通过调用静态工厂方法创建Bean

  • 静态工厂方法:将对象创建的过程封装到静态方法中.`当客户端需要对象时,只需要简单的调用静态方法,而不用关心创建对象的细节
  • 要声明通过静态方法创建的Bean,需要在Bean的class属性里指定拥有该工厂的类,同时在factory-method属性里指定该工厂方法的名称.最后,使用<constructor-arg>元素为该方法传递方法参数

代码示例:

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
package factory;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:02
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/12 14:02
* @Version 1.0
*/
class Car {
private String brand;
private int speed;
private double price;

Car(String brand, int speed, double price) {
this.brand = brand;
this.speed = speed;
this.price = 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;
}
}

2. 通过调用实例工厂方法创建Bean

  • 实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里.当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
  • 要声明通过实例工厂方法创建的Bean
    • 在Bean的factory-bean属性里指定拥有该工厂方法的Bean
    • factory-method属性里指定该工厂方法的名称
    • 使用<constructor-args>元素为工厂方法传递方法参数

代码示例:

instanceFactory.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
package factory;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:19
* @Version 1.0
*/

import java.util.HashMap;
import java.util.Map;

/**
* @author Sheng Wenzeng
* @ClassName InstanceFactory
* @Description TODO 先需要创建工厂本身,再调用工厂的实例方法来返回Bean的实例
* @Date 2019/8/12 14:19
* @Version 1.0
*/
public class InstanceFactory {
private Map<String, Car> cars = new HashMap<>();

public InstanceFactory() {
cars.put("Audi", new Car("Audi", 100, 400000));
cars.put("Ford", new Car("Ford", 50, 200000));
}

public Car getCar(String name) {
return cars.get(name);
}
}

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
package factory;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:02
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/12 14:02
* @Version 1.0
*/
class Car {
private String brand;
private int speed;
private double price;

Car(String brand, int speed, double price) {
this.brand = brand;
this.speed = speed;
this.price = 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 factory;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:08
* @Version 1.0
*/

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

/**
* @author Sheng Wenzeng
* @ClassName Main
* @Description TODO
* @Date 2019/8/12 14:08
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("factory/factory.xml");
Car car1 = (Car) applicationContext.getBean("car1");
System.out.println(car1);
}
}

factory.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?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">

<!--配置工厂的实例-->
<bean id="instanceFactory" class="factory.InstanceFactory"/>

<bean id="car1" factory-bean="instanceFactory" factory-method="getCar">
<constructor-arg value="Ford"/>
</bean>
</beans>

运行结果:

1
Car{brand='Ford', speed=50, price=200000.0}

通过FactoryBean配置Bean

配置Bean的第三种方式:FactoryBean

FactoryBean需要实现FactoryBean接口,接口中有三个方法:

  • getObject()
  • getObjectType()
  • isSingleton()

FactoryBean.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
package factoryBean;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:38
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName FactoryBean
* @Description TODO 自定义的FactoryBean,需要实现Spring提供的接口FactoryBean
* @Date 2019/8/12 14:38
* @Version 1.0
*/
public class FactoryBean implements org.springframework.beans.factory.FactoryBean<Car> {

private String brand;

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

//返回Bean的对象
@Override
public Car getObject() throws Exception {
return new Car(brand, 100, 400000);
}

//返回Bean的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}

@Override
public boolean isSingleton() {
return true;
}
}

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
package factoryBean;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:02
* @Version 1.0
*/

/**
* @author Sheng Wenzeng
* @ClassName Car
* @Description TODO
* @Date 2019/8/12 14:02
* @Version 1.0
*/
class Car {
private String brand;
private int speed;
private double price;

Car(String brand, int speed, double price) {
this.brand = brand;
this.speed = speed;
this.price = 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 factoryBean;/*
* @Author Sheng WenZeng
* @Date 2019/8/12 14:43
* @Version 1.0
*/

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

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

BeanFactory.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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">
<!--
通过FactoryBean来配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性,但实际上返回的是getObject()方法返回的实例
-->
<bean id="car" class="factoryBean.FactoryBean">
<property name="brand" value="Audi"/>
</bean>
</beans>

运行结果为:

1
Car{brand='Audi', speed=100, price=400000.0}

通过注解配置Bean

配置Bean除了基于XML文件的形式,还可以基于注解的方式(基于注解配置Bean&基于注解装配Bean的属性)

在ClassPath中扫描组件

  • 组件扫描(component scanning):Spring能够从classpath下自动扫描侦测和实例化具有特定注解的组件

  • 特定组件包括:

    • @Component:基本注解,标识了一个受Spring管理的组件
    • @Respository:标识永久层组件
    • @Service:标识服务层(业务层)组件
    • @Controller:标识表现层组件
  • 对于扫描到的组件,Spring有默认的命名策略:通过非限定类名,第一个字母小写.也可以在注解中通过value属性值标识组件的名称

  • 当在组件上使用了特定的注解之后,还需要在Spring的配置文件中声明<context:component-scan>:

    • base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类

    • 当需要扫描多个包时,可以使用逗号分隔

    • 如果仅希望扫描特定的类而非基类包下的所有类,可使用resource-patten属性过滤特定的类,示例:

      1
      2
      3
      <context:component-scan
      base-package="com.swzdl.spring.beans"
      resource-patten="autowire/*.class"/>
  • <context:include-filter>子节点表示要包含的目标类

  • <context:exclude-filter>子节点表示要排除在外的目标类

  • <context:component-scan>下可以拥有若干个<context:include-filter><context:exclude-filter>子节点

评论

Your browser is out-of-date!

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

×