Spring的核心是Spring容器,容器负责管理应用中的组件的生命周期,它负责创建这些组件的创建(bean)和依赖管理
spring配置bean的可选方案有三种:
- 在XML中进行显示配置
<bean id="math" class="xxx.Math"/><!--必须使用全限定的类名-->
<bean id="College" class="xxx.CollegeStudent">
<constructor-arg ref="math"/>
</bean>
如上,是XML常见配置,College通过构造方法装配Math。当遇到构造方法参数包含集合类的时候该怎么处理呢,例public SSStudent(String author,int score,List
<bean id="ssstudent" class="xxxx.SssStudent" >
<constructor-arg value="李老师"/>
<constructor-arg value=100/>
<constructor-arg >
<list>
<ref bean ="oneChoseTitle"/>
<ref bean ="multiChoseTitle"/>
...
</list>
</constructor-arg >
</bean>
XML除了利用构造方法装配bean,还可以通过set方法
public class JStudent implements Student{
private Subject subject;
}
//...省略get/set方法
Jstudent除了默认构造器没有任何构造器,当我们通过XML作如下配置
<bean id="jstudent" class="xxx.JStudent"/>
上面的配置在Spring创建bean时没有任何问题,但是当它调用exam方法时会出现NULLPOINTEREXCEPTION,因为并没有注入Subject属性。下面我们作如下修改:
<bean id="jstudent" class="xxx.JStudent">
<property name="subject" ref="math"/>
</bean>
修改后的代码,通过set方法将Subject注入了Student中。
2. 在Java中进行显示配置
通常情况下Spring推荐通过组件扫描和自动装配实现Spring的自动化配置,但是在没写场景下比如,要讲第三方库的组件装配到应用中,这种情况下是无法在它的类上添加@Component和@Autowired注解的,这个时候就可以使用显示的装配(XML/Java)。因为Java显示配置更强大、类型安全并且对重构友好,我们选择显示的Java配置
@Configuration
@ComponentScan
public class StudentConfig{
}
如上所见虽然JavaConfig配置也是用Java类,但它与一般Java类还是有区别的,它不包含任何业务逻辑,也不侵入到任何业务逻辑代码中,一般为了区分都会放到单独包中。下面我们看一下,JavaConfig是如何声明bean的
@Bean
public Subject math(){
return new Math();
}
@Bean注解会通知Spring这个方法将产生一个bean对象,默认名字是math,如果需要制定name的话可以这样
@Bean(name="mathSubject")//指定bean的name
public Subject math(){
return new Math();
}
下面我们来声明一个Student类依赖于Subject
public class CollegeStudent implents Student(){
private Subject subject;
public CollegeStudent(Subject subject){
this.subject = subject;
}
public void exam(){
subject.examination();
}
}
显然ColledgeStudent类依赖于Subject类,接下来通过JavaConfig来实现bean之间依赖关系的维护
@Bean
public ColledgeStudent student(Subject subject){
return new ColledgeStudent(subject);
}
这里CollegeStudent请求一个Subject类作为参数,Spring创建CollegeStudent时候,会传入一个Subject到配置方法中。
3. 隐式的bean发现机制和自动装配
spring通过两个角度来描述自动化装配
1. 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean
2.自动装配(autowiring):Spring自动满足bean之间的依赖关系
示例:
public interface Subject(){
void examination();
}
Subject是一个科目接口类,它定义了操作考试examination,它将学生的任意实现和考试本身的耦合降到了最小,现在我们来创建一个Subject的实现:
@Component
public class Math implements Subject{
private author="张老师";
private int totalScore = 100;
public void examination(){
System.out.println("出卷人:"+author+"--总分:"+score);
}
}
如上所述Subject实现Math,内容不重要,该类使用了@Component注解,表示该类将作为组件类,并让Spring为这个类创建bean,不过组件扫描默认是不启用的,需要显示配置Spring,让其寻找导游@Component的类并创建bean。如下:
@Configuration
@ComponentScan(basePackages="xxx")//指定扫描路径,可以为复数@ComponentScan(basePackages={"xxx","yyy"}) 默认为同包下
public class StudentConfig{}
上面就是一个通过Java类进行显示配置的文件。@Component会启动Spring的组件扫描功能,并默认扫描该文件同一包下的所有子包,查找带有@Component注解的类,并创建bean。可以看到上面例子里包路径指定类型为String类型,但这种方法其实是类型不安全的(not-type-safe),如果你重构代码的话,指定的基础包会出现错误。所以我们还可以通过指定扫描对象为包中所含的类或接口
<@ComponentScan(basePakages={xxxx.class,yyyy.class})>//通过包中类或接口指定扫描范围
除了通过上面的方式还可以通过XML文件来启动组件扫描
<context:component-scan base-pakage=""/>
在base-pakage中写入需要扫描的包位置即可。
下面我们通过为bean添加注解实现自动装配
@Component
public class CollegeStudent implenents Student{
private Subject subject;
@Autowired
public CollegeStudent(Subject subject){
this.subject = subject;
}
public void exam(){
subject.examination();
}
}
如上诉代码所示@Autowired注解在构造器上,从而Spring容器在创建CollegeStudent的bean对象的时候会调用其构造方法传入一个Subject类型的bean对象。当然也可以通过set方法装配
@Autowired
public void setSubject(Subject subject){
this.subject = subject;
}
实际上任何一个满足条件的方法都可以装配bean,例如我们创建一个insetSubject方法
@Autowired
public void insertSubject(Subject subject){
this.subject = subject;
}