一,介绍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方法 用面向接口的方法能松耦.接口的内容并不重要
1 //make an animal interface 2 pack test; 3 4 public interface Animal{ 5 void play(): 6 }
2.创建一个动物的实现类,可以多个实现.(用到了Component注解)
1 package test; 2 3 @Component 4 public class dog implements Animal{ 5 6 private String title = ''wang wang wang ....''; 7 private String boy ="hahahahha"; 8 9 public void play(){ 10 System.out.println("dog"+title+"boy"+boy); 11 } 12 }
@Component注解的意思是:标明该类会作为组件类,并告知Spring要为这个类创建bean.不需要配置XML或者JavaConfig.
但是我们还要启动组件扫描,因为组件扫描默认是不启用的. 所以需要显式的配合Spring,让他去寻找带有@Component的类,并为其创建Bean.
3.
3.1创建组件扫描的配置类
1 package test; 2 3 @Configuration 4 @ComponentScan 5 public class DogConfig{ 6 7 }
这个类通过Java代码定义了Spring 的装配规则,并没有显式的声明任何bean.因为他使用了@ComponentScan注解
@ComponentScan能在Spring中启用组件扫描,还会默认扫描与配配置类相同包下带有@Component注解的类并创建一个bean.
3.2还有一种开启组件扫描的配置时利用XML,原理是使用Spring context命名空间的<context:component-scan>元素.
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 5 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 7 8 <context:component-scan base-package = "test"/> 9 </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提供的另外一种方法,就是将其指定为包中所含的类或接口.
1 @Cnfiguration 2 @ComponentScan(basePackageClasses={Dog.class,Cat.class}) 3 public class DogConfig{ 4 5 }
五,通过bean添加注解实现自动装配
上面我们学会了怎么将类设置为扫描类,让容器对对象的生老病死负责,但是他们仍然一个个是独立的,怎么让对象之间的相互依赖达成呢? 这就要用到自动注入:将组建扫描得到的Bean和他们的依赖装配在一起.
在自动装配的过程中,会在spring应用上下文中寻找匹配某个bean需求的其他Bean.然后用@Autowired声明.
1 package test; 2 3 @Component 4 public class Dog implements Animal{ 5 6 private Dog dog; 7 @Autowired 8 public Dog(Dog dog){ 9 this.dog = dog; 10 } 11 public void play(){ 12 dog.play(;) 13 } 14 }
这表名当Spring在创建DogBean的时候,会通过构造器来进行实例化并且会传入一个可设置的Dog类型bean.
@Autowired注解不仅能够用在构造器上,还能用在setter方法上.比如:
@Autowired public void setDog(Dog dog){ this.dog = dog; }
@Autowired注解可以用在构造方法,成员属性和其他方法,Spring都会满足参数上所声明的依赖,为防止在应用上下文创建的时候匹配不到bean二报错. 我们可以将@Autowired的required属性设置为false;
1 @Autowired(required=false) 2 public void setDog(Dog dog){ 3 this.dog = dog; 4 }
但是要谨慎的运用required属性,因为如果自动装配没有匹配到bean,并且没有进行null判断会报空指针.
@Autowired是Spring独有的注解. 可以用@Injecgt注解去取代.
@Inject和@Named注解都来源于JAva依赖注入规范.
到此通过组件扫描和自动扫描的基础知识我们已经了解了
明天会学习通过Java代码装配bean,xml配置装配bean.