一,介绍Bean的装配机制
在Spring中,容器负责对象的创建并通过DI来协调对象之间的关系.但是我们要告诉Spring创建哪些Bean并且如何将其装配在一起.,装配wiring就是DI依赖注入的本质.
Spring装配bean有几种机制:
- 在XML中进行显式配置
- 在Java中进行显式配置
- 隐式的bean发现机制和自动装配
三种机制可能会给我们选择上造成困扰?哪个好?是不是不同情况有不同的选择?
答:会在很多场景下,选择哪种机制完全取决于个人的喜好,但是我推荐用自动装配,可以自动装配我们为什么还要费力气去配置.而且三种机制可以互相搭配,你可以用XML装配一些Bean,使用Spring基于Java的配置(JavaConfig)来装配另一些Bean,剩余的bean让Spring去自动发现装配.
但是,尽可能的用自动装配,显式装配越少越好.当不得不显式装配的时候(比如,有些源码不是你来维护的,但你要为这些代码配置bean的时候),推荐使用JavaConfig,因为他XML更安全更强大.只有在你想用XML的命名空间,并且在JavaConfig中没有同样的实现,才选择XML.
二.自动化装配Bean
Spring从两个方面实现自动装配:
- 组件扫描(component scanning):Spring会自动发现应用上下文所创建的bean.
- 自动装配(Autowiring):Spring会自动满足bean之间的依赖.
组件扫描和自动装配组合在一起能完美的降级显式配置.
举例:创建一个动物类animal,Spring会发现并将它创建成一个bean.在创建一个people类,并将animal类注入进来.
1.先创建一个动物接口,定义了有个play方法 用面向接口的方法能松耦.接口的内容并不重要
//make an animal interface
pack test; public interface Animal{
void play():
}
2.创建一个动物的实现类,可以多个实现.(用到了Component注解)
package test; @Component
public class dog implements Animal{ private String title = ''wang wang wang ....'';
private String boy ="hahahahha"; public void play(){
System.out.println("dog"+title+"boy"+boy);
}
}
@Component注解的意思是:标明该类会作为组件类,并告知Spring要为这个类创建bean.不需要配置XML或者JavaConfig.
但是我们还要启动组件扫描,因为组件扫描默认是不启用的. 所以需要显式的配合Spring,让他去寻找带有@Component的类,并为其创建Bean.
3.
3.1创建组件扫描的配置类
package test; @Configuration
@ComponentScan
public class DogConfig{ }
这个类通过Java代码定义了Spring 的装配规则,并没有显式的声明任何bean.因为他使用了@ComponentScan注解
@ComponentScan能在Spring中启用组件扫描,还会默认扫描与配配置类相同包下带有@Component注解的类并创建一个bean.
3.2还有一种开启组件扫描的配置时利用XML,原理是使用Spring context命名空间的<context:component-scan>元素.
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <context:component-scan base-package = "test"/>
</beans>
三 为组件扫描的bean命名
Spring应用上下文中所有的bean都会有一个ID.如果没有明确那么ID则是类名首字母小写.当然我们也可以认为的设置一个自己中意的ID,我们要做的就是讲ID作为值传递给@Component注解,比如我想为Dog类创建ID为gouzi :
@Component("gouzi")
public class Dog implements Animal{
...
} //huozhe yong @Named @Named("gouzi")
public class Dog implements Animal{
...
}
四.设置组件扫描的基础包
我们之前说了@ComponentScan注解会默认扫描当前包及其子包下的带有@Component注解的类并为其创建一个bean. 但是事实上我们是可以指定的.
@Cnfiguration
@ComponentScan("Dog")
public class DogConfig{ } //huozhe @Cnfiguration
@ComponentScan(basePackages="Dog")
public class DogConfig{ } //huozhe
@Cnfiguration
@ComponentScan(basePackages={"Dog","Cat"})
public class DogConfig{ }
但是以String类型的基础包在代码重构的情况下是不安全的.所以我们用@ComponentScan提供的另外一种方法,就是将其指定为包中所含的类或接口.
@Cnfiguration
@ComponentScan(basePackageClasses={Dog.class,Cat.class})
public class DogConfig{ }
五,通过bean添加注解实现自动装配
上面我们学会了怎么将类设置为扫描类,让容器对对象的生老病死负责,但是他们仍然一个个是独立的,怎么让对象之间的相互依赖达成呢? 这就要用到自动注入:将组建扫描得到的Bean和他们的依赖装配在一起.
在自动装配的过程中,会在spring应用上下文中寻找匹配某个bean需求的其他Bean.然后用@Autowired声明.
package test; @Component
public class Dog implements Animal{ private Dog dog;
@Autowired
public Dog(Dog dog){
this.dog = dog;
}
public void play(){
dog.play(;)
}
}
这表名当Spring在创建DogBean的时候,会通过构造器来进行实例化并且会传入一个可设置的Dog类型bean.
@Autowired注解不仅能够用在构造器上,还能用在setter方法上.比如:
@Autowired
public void setDog(Dog dog){
this.dog = dog;
}
@Autowired注解可以用在构造方法,成员属性和其他方法,Spring都会满足参数上所声明的依赖,为防止在应用上下文创建的时候匹配不到bean二报错. 我们可以将@Autowired的required属性设置为false;
@Autowired(required=false)
public void setDog(Dog dog){
this.dog = dog;
}
但是要谨慎的运用required属性,因为如果自动装配没有匹配到bean,并且没有进行null判断会报空指针.
@Autowired是Spring独有的注解. 可以用@Injecgt注解去取代.
@Inject和@Named注解都来源于JAva依赖注入规范.
到此通过组件扫描和自动扫描的基础知识我们已经了解了
明天会学习通过Java代码装配bean,xml配置装配bean.