参考代码下载github:https://github.com/changwensir/java-ee/tree/master/spring4
一、Bean的配置方式
Bean 的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean
1-1.通过静态工厂方式配置Bean
--•
调用
静态工厂方法
创建
Bean
是将
对象创建的过程封装到静态方法中
.
当客户端需要对象时
,
只需要简单地调用静态方法
,
而不同关心创建对象的细节
.
--•
要声明通过静态方法创建的
Bean,
需要在
Bean
的
class
属性里指定拥有该工厂的方法的类
,
同时在
factory-method
属性里指定工厂方法的名称
.
最后
,
使用
<
constrctor-arg
>
元素为该方法传递方法参数
.
1-2.通过实例工厂方式配置Bean
•
实例工厂方法
:
将对象的创建过程封装到另外一个对象实例的方法里
.
当客户端需要请求对象时
,
只需要简单的调用该实例方法而不需要关心对象的创建细节
.
•
要声明通过实例工厂方法创建的
Bean
–
在
bean
的
factory-bean
属性里指定拥有该工厂方法的
Bean
–
在
factory-method
属性里指定该工厂方法的名称
–
使用
construtor-arg
元素为工厂方法传递方法参数
/**
* InstanceCarFactory:实例工厂方法
* 实例工厂的方法,即需要先创建工厂本身,再调用工厂的实例方法来返回bean的实例
*
* @author Lcw 2015/11/12
*/
public class InstanceCarFactory {
private Map<String, Car> cars = null;
public InstanceCarFactory() {
cars = new HashMap<String, Car>();
cars.put("audi", new Car("audi", 500000));
cars.put("ford", new Car("ford", 600000));
}
public Car getCar(String brand) {
return cars.get(brand);
}
}
/**
* StaticCarFactory:静态工厂方法:直接调用某一个类的静态方法就可以返回Bean实例
*/
public class StaticCarFactory {
private static Map<String , Car> cars = new HashMap<String, Car>();
static {
cars.put("audi",new Car("audi", 30000));
cars.put("ford",new Car("ford", 40000));
}
//静态工厂方法: 注意:要在配置文件XML里配置Car而不是StaticCarFactory
public static Car getCar(String name) {
return cars.get(name);
}
}
<?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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--通过静态工厂方法来配置bean, 注意不是配置静态工厂方法实例,而是配置bean实例-->
<!--factory-method: 指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数-->
<bean id="car1" class="Spring4_IOC.bean.factory.StaticCarFactory"
factory-method="getCar">
<constructor-arg value="audi"/>
</bean>
<!--配置实例工厂的实例-->
<bean id="carFactory" class="Spring4_IOC.bean.factory.InstanceCarFactory"/>
<!-- 通过实例工厂方法来配置bean-->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="ford"/>
</bean>
</beans>
/**
* Bean 的配置方式:-、通过全类名(反射);二、通过工厂方法(静态工厂方法 & 实例工厂方法);三、FactoryBean
*
* 静态工厂方法:直接调用某一个类的静态方法就可以返回Bean实例
* 实例工厂方法:实例工厂的方法,即需要先创建工厂本身,再调用工厂的实例方法来返回bean的实例
*/
@Test
public void testStaticFactory() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-factory.xml");
//测试静态工厂方法
Car car1 = (Car) ctx.getBean("car1");
System.out.println(car1);
//实例工厂方法
Car car2 = (Car) ctx.getBean("car2");
System.out.println(car2);
}
1-3.实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
•
Spring
中有两种类型的
Bean,
一种是普通
Bean,
另一种是工厂
Bean,
即
FactoryBean
.
•
工厂
Bean
跟普通
Bean
不同
,
其返回的对象不是指定类的一个实例
,
其返回的是该工厂
Bean
的
getObject
方法所返回的对象
/**
* CarFactoryBean:自定义的factoryBean需要实现FactoryBean
*/
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public CarFactoryBean() {
}
//下面是三个实现方法
//返回bean的对象
public Car getObject() throws Exception {
return new Car("BMW" , 500000);
}
//返回bean的类型Class<?> 中?表示一个未知的类
public Class<?> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return true;
}
}
<?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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--
通过factoryBean来配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性
但实际返回的实例确是FactoryBean的getObject()返回的实例-->
<bean id="car" class="Spring4_IOC.bean.CarFactoryBean">
<property name="brand" value="BMW"/>
</bean>
</beans>
/**
* Bean 的配置方式:-、通过全类名(反射);二、通过工厂方法(静态工厂方法 & 实例工厂方法);三、FactoryBean
*
* 测试FactoryBean
* Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean, 即FactoryBean
*/
@Test
public void testFactoryBean() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-beanFactory.xml");
Car car = (Car) ctx.getBean("car"); //注意这个在类是Car!
System.out.println(car);
}
二、Bean的配置形式
配置形式:基于 XML 文件的方式;基于注解的方式(基于注解配置 Bean;基于注解来装配 Bean 的属性)在 classpath 中扫描组件
•
组件扫描
(componentscanning): Spring
能够
从
classpath
下自动扫描
,
侦测和实例化具有特定注解的组件
.
•
特定组件包括
:
–
@Component:
基本注解
,
标识了一个受
Spring
管理的组件
–
@
Respository
:
标识持久层组件
–
@Service:
标识服务层
(
业务层
)
组件
–
@Controller:
标识表现层
组件
•
对于扫描到的组件
,
Spring
有默认的命名策略
:
使用非限定类名
,
第一个字母小写
.
也可以
在注解中通过
value
属性值标识组件的名称
•
当在组件类上使用了特定的注解之后
,
还需要在
Spring
的配置文件中
声明
<
context:component-scan
>
:
–
base-package
属性指定一个需要扫描的基类包
,
Spring
容器将会扫描这个基类包里及其子包中的所有类
.
–
当需要扫描多个包时
,
可以使用逗号分隔
.
–
如果仅希望扫描特定的类而非基包下的所有类,可使用
resource-pattern
属性过滤特定的类,示例:
–
<
context:include-filter
>
子节点表示要包含的目标类
–
<
context:exclude-filter
>
子节点表示
要排除在外的
目标
类
–
<
context:component-scan
>
下可以拥有若干个
<
context:include-filter
>
和
<
context:exclude-filter
>
子节点
以下 类那放在这个文件下Spring4_IOC.annotation
@Component
public class TestObject {
}
respository接口跟实现类
public interface UserRepository {
void save();
}
//接口实现一般用接口名
@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository {
public void save() {
System.out.println("UserRepository Save...");
}
}
Service层跟controller
@Service
public class UserService {
//@Autowired(required=false) //如果没有这个类,输出为null
@Autowired
private UserRepository userRepository;
public void add() {
System.out.println("UserService add...");
userRepository.save();
}
}
@Controller
public class UserController {
@Autowired
private UserService userService;
public void execute() {
System.out.println("UserController execute...");
userService.add();
}
}
<?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">
<!--指定Spring IOC容器扫描的包-->
<!--可以通过resource-pattern指定扫描的资源-->
<!--<context:component-scan base-package="Spring4_IOC.annotation"
resource-pattern="repository/*.class"></context:component-scan>-->
<!--exclude-filter: 子节点指定排除哪些指定表达式的组件-->
<!--include-filter:子节点指定包含哪些表达式的组件,该子节点需要use-default-filters="false"配合使用-->
<context:component-scan base-package="Spring4_IOC.annotation" >
<!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!--<context:exclude-filter type="assignable" expression="com.changwen.spring4.annotation.repository.UserRepository"/>-->
<!--<context:include-filter type="assignable" expression="com.changwen.spring4.annotation.repository.UserRepository"/>-->
</context:component-scan>
</beans>
@Test
public void testAnnotation() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-annotation.xml");
TestObject to = (TestObject) ctx.getBean("testObject");
System.out.println(to);
//类UserController第一个字母小写 userController
UserController userController = (UserController) ctx.getBean("userController");
System.out.println(userController);
userController.execute();
UserService userService = (UserService) ctx.getBean("userService");
System.out.println(userService);
UserRepository userRepository = (UserRepository) ctx.getBean("userRepository");
System.out.println(userRepository);
}
<
context:include-filter
>
和
<
context:exclude-filter
>
子
节点支持多种类型的过滤表达式
2-1.组件装配
•
<
context:component-scan
>
元素还会自动注册
AutowiredAnnotationBeanPostProcessor
实例
,
该实例可以自动装配具有
@
Autowired
和
@Resource
、
@Inject
注解
的属性
.
1).使用 @Autowired自动装配Bean
•
@
Autowired
注解自动装配
具有兼容类型
的单个
Bean
属性
–
构造器
,
普通字段
(
即使是非
public),
一切具有参数的方法都可以应用
@
Authwired
注解
–
默认
情况下
,
所有使用
@
Authwired
注解的属性都需要被设置
.
当
Spring
找不到匹配的
Bean
装配属性时
,
会抛出异常
,
若某一属性允许不被设置
,
可以设置
@
Authwired
注解的
required
属性为
false
–
默认
情况下
,
当
IOC
容器里存在多个类型兼容的
Bean
时
,
通过类型的自动装配将无法工作
.
此时可以在
@Qualifier
注解里提供
Bean
的名称
.
Spring
允许对方法的入参标注
@
Qualifiter
已指定注入
Bean
的名称
–
@
Authwired
注解也可以应用在
数组类型
的属性上
,
此时
Spring
将会把所有匹配的
Bean
进行自动装配
.
–
@
Authwired
注解也可以应用在
集合属性
上
,
此时
Spring
读取该集合的类型信息
,
然后自动装配所有与之兼容的
Bean.
–
@
Authwired
注解用
在
java.util.Map
上时
,
若该
Map
的键值为
String,
那么
Spring
将自动装配与之
Map
值类型兼容的
Bean,
此时
Bean
的名称作为键值
2).使用 @Resource或@Inject自动装配Bean
•
Spring
还支持
@Resource
和
@Inject
注解,这两个注解和
@
Autowired
注解的功用类似
•
@Resource
注解要求提供一个
Bean
名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为
Bean
的名称
•
@Inject
和
@
Autowired
注解
一样也是按类型匹配注入的
Bean
,但没有
reqired
属性
•
建议使用
@
Autowired
注解
三、泛型依赖注入
•
Spring 4.x
中可以为子类注入子类对应的泛型类型的成员变量的引用
public class BaseRepository<T> {
}
public class BaseService<T> {
@Autowired
protected BaseRepository<T> repository;
public void add() {
System.out.println("add...");
System.out.println(repository);
}
}
@Service
public class UserService extends BaseService<User> {
}
public class User {
private String userName;
private List<Car> cars;
private String wifeName;
public String getWifeName() {
return wifeName;
}
public void setWifeName(String wifeName) {
System.out.println("setWifhName: " + wifeName);
this.wifeName = wifeName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
public User() {
System.out.println("User's Construtor...");
}
@Override
public String toString() {
return "User [userName=" + userName + ", cars=" + cars + "]";
}
public void init(){
System.out.println("init method...");
}
public void destroy(){
System.out.println("destroy method...");
}
}
@Repository
public class UserRepository extends BaseRepository<User>{
}
配置文件
<?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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="Spring4_IOC.di">
</context:component-scan>
</beans>
/**
* Spring 4.x 新特性:泛型依赖注入
*/
@Test
public void testDI() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-generic.xml");
Spring4_IOC.di.UserService userService = (Spring4_IOC.di.UserService) ctx.getBean("userService");
System.out.println(userService);
userService.add();
}
Spring4_IOC.di.UserService@225a8897 add... Spring4_IOC.di.UserRepository@65bd831f |
•
Spring
允许通过
<import>
将多个配置文件引入到一个文件中,进行配置文件的集成。这样在启动
Spring
容器时,仅需要指定这个合并好的配置文件就可以。
•
i
mport
元素的
resource
属性支持
Spring
的标准的路径资源