要装配bean,首先应该知道bean应该要装到哪里去,在spring中容纳bean(也就是对象实例)的东西叫容器。容器是spring的核心,容器里面装着各种各样的对象实例Bean。
spring的容器总体来讲有两个类型,一个是bean工厂,另一个是应用上下文(或者叫应用环境)ApplicationContext。我们常用的是应用上下文这个容器。
装配Bean的三种方式
- 在XML配置文件中进行显示配置(最次选择)
- 在Java配置类中进行显示配置(次优选择)
- 使用注解的spring隐式自动发现机制和自动装配(最优选择)
自动装配
第一步:创建基本显示配置类,开启组件扫描
实现自动装配仍然需要一定的显示配置,首先我们仍然需要一个配置类,这个配置类中什么都不需要写,但是需要加上必要的注解。
@Configuration
@ComponentScan(value = {"aop"})
public class AopConfig {
}
@Configuration
@Configuration注解会告诉spring这是一个配置类,这是必须的注解
@ComponentScan
@ComponentScan注解指明需要扫描哪些包下的类,并为他们创建实例放入spring容器中,也就是开启组件扫描。
@ComponentScan的基本使用:
如果直接在配置类上贴上@ComponentScan注解,表示只扫描被贴上注解的配置类所在的包以及所在包的子包。
@Configuration
@ComponentScan
public class AopConfig {
}
但是我们很多时候需要将配置类单独放到一个包中。这样就他的默认扫描范围就不满足我们的要求。于是我们可以这样修改。可以指定需要扫描的包,值是一个string类型的数组,值的具体元素为包得类路径,所以可以指定多个扫描的范围。
@Configuration
@ComponentScan(value = {"aop"})
public class AopConfig {
}
明确的指明所设置的包是基础包
@Configuration
@ComponentScan(basePackages = {"com.ctbu.spring_demo1.config"})
public class AppConfig {
}
扫描的基础包可以有多个,支持接收集合
@Configuration
@ComponentScan(basePackages = {"com.ctbu.spring_demo1.config", "com.ctbu.spring_demo1.controller"})
public class AppConfig {
}
支持类作为扫描标记,使用这种方式的话对重构代码很友好,spring会自动去寻找这个类,并把这个类所在的包作为扫描的基础包。如果需要的时候,可以创建一个空的接口为组件扫描提供标记。
@Configuration
@ComponentScan(basePackageClasses = Person.class)
public class AppConfig {
}
第二步:标注需要加入容器的类
@Component
public class Dance implements Performance {
}
@Component
@Component注解会将贴上注解的类作为spring的组件扫描进spring容器中。
@Component详解
spring应用上下文会给所有的bean都分配一个id,作为这个对象实例的唯一标识,当我们没有明确的指定这个id的时候,spring会自动为其分配一个id
情况 | 措施 |
---|---|
在xml配置文件中没有明确指定beanID | spring会以全限定类名写作为BeanID |
在组件扫描中没有明确指定BeanID | spring会以类名的首字母小写作为BeanID |
在Java配置类中没有明确指定BeanID | spring会以方法名作为BeanID |
如果想自定义beanID
情况 | 措施 |
---|---|
在组件扫描中 | 指定@Component的值:@Component("person") |
在xml配置文件中 | 指定bean的id属性 :id="person" |
在Java配置类中 | 指定@Bean注解的值:@Bean(name=“person”) |
spring还支持使用@Name来为bean(对象实例)命名,用法:@Name(“person”),但是此方法基本不使用。
第三步:使用容器中的组件
public class MagicTest {
@Autowired
private Performance magic;
@Test
public void perform() {
magic.perform(20);
SpecialService service = (SpecialService) magic;
service.specialService();
}
}
@Autowired
@Autowired注解表示spring会对被标注的变量使用自动装配,spring会从容器中找出适合的bean实例,并将他赋值给这个变量。
@Autowired注解的使用
@Autowired注解不仅可以使用在一般的变量上,还可以使用在构造器方法,和属性的setter方法上。实际上@Autowired注解可以用在类中的任何方法上,spring会尽力去满足方法上所声明的依赖。
在自动注入的过程中,如果spring没有在spring容器中找到合适的bean进行注入,spring就会抛出异常,为了避免这个异常的发生,我们以及将@Autowired注解的required属性设置为false
@Autowired(required = false)
但此时也要注意空指针异常的情况。
同样@Autowired注解也有替代方案@Inject,但是我们基本不使用这个注解,@Autowired更加适合spring,也更加让人容易接收。
使用Java配置类进行显示配置
为什么要使用Java配置类的方式?尽管自动装配已经很强大了,对于我们自己写的bean,自动装配完全可以满足要求,但是,对于第三方的bean,比如datesource等,我们无法在其源码上贴上@Component注解,因此必须通过new其对象来创建对应的bean,而基于xml配置文件的方式也可以达到这样的效果,但是xml实在是太繁琐了。
第一步:创建配置类
@Configuration
public class AopConfig {
}
如上代码是一个完整的基于Java配置类的组件装配设置。
如果完全使用Java配置类来为spring容器中添加bean,那么就可以不用开启组件扫描。
@Configuration
@Configuration注解表示被标注的类是一个配置类,spring容器对象可以从这个配置类中加载需要装入容器的bean实例。
第二步:声明Bean
@Configuration
public class AopConfig {
@Bean
public Dance dance(){
return new Dance();
}
}
如上代码,当spring加载这个配置类的时候就会把创建的对象实例,作为组件,放入到spring容器中。默认情况下,这里创建的bean的名称ID为方法名,但是我们也可以自己指定名称ID。(在上面的表格中有详细归纳)
@Bean(name = "dance")
@Bean
@Bean注解会告诉spring这个被标注的方法会返回一个对象,而这个返回的对象要注册为spring容器中的bean
第三步:使用组件
这一步和自动装配是一样的,同样可以使用@Autowired进行注入。
Java配置类装配存在引用的bean
很多时候,我们在装配一个bean的时候,这个bean可能引用了其他的bean实例,这样的配置在Java配置类中同样可以实现。下面的代码展示如何装配存在对象引用的bean
public class Man {
Food food;
public Man(Food food){
this.food = food;
}
public void eat() {
System.out.println("吃:" + this. food);
}
}
在上面的代码中,可以知道,如果要通过Java配置类的方式将Man这个bean放入spring容器中,那么newMan对象的时候需要有一个Food对象的引用。可以这样做。
@Configuration
@ComponentScan(basePackageClasses = Person.class)
public class AppConfig {
@Bean
public Food food(){
return new Food();
}
@Bean
public Man man(){
return new Man(food());
}
}
直接在man这个方法中调用food()方法,以为food方法一定会产生一个Food类型的实例bean。
还有一种更加简单的当时来实现有引用的装配。
@Configuration
@ComponentScan(basePackageClasses = Person.class)
public class AppConfig {
@Bean
public Food food(){
return new Food();
}
@Bean
public Man man(Food food){
return new Man(food);
}
}
如上Java配置类,直接将要引用的对象作为方法的形参传入,在创建对应bean的时候可以直接使用这个形参,spring会自动满足这个依赖。而且,要强调的是,这个要传入的形参food并不一定要求和Man在同一个配置类中,它可以是通过自动装配实现的,也可以在其他Java配置类中,甚至可以是在xml配置文件中,只要spring能在容器中发现他的存在。
使用XML配置文件进行装配
使用XML配置文件进行bean的装配之前,首先需要创建一个xml配置文件,这一步相当于Java配置类中的@Configuration注解的作用。
<?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">
</beans>
声明一个简单的Bean
<?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 class="com.ctbu.xmlconfigtest.domain.Person"/>
</beans>
如上就声明了一个最简单的,以XML配置文件形式装配的bean实例
这里没有明确指定bean的id,所以默认情况下,会以类的全限定名称,也就是:com.ctbu.xmlconfigtest.domain.Person 作为bean的默认id,但是这太麻烦了,每一次引用难道都要写这么大一串?
因此,可以使用id属性指定bean的id;
<?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="person" class="com.ctbu.xmlconfigtest.domain.Person"/>
</beans>
XML中构造器参数的注入
XML配置文件中也会存在要配置对象引用的时候,这个使用有两种方式
- <constructor-arg/>元素
- c-命名空间:spring3.0后引入的功能
使用<constructor-arg / >元素
<?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="person" class="com.ctbu.xmlconfigtest.domain.Person"/>
<bean id="work" class="com.ctbu.xmlconfigtest.domain.Work">
<constructor-arg ref="person"/>
</bean>
</beans>
可以看到,创建work对象的时候需要注入一个person对象的引用,使用<constructor-arg ref="person"/>元素实现了这一需求。
使用c-命名空间
这里的c:后面使用了构造器参数的名称
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person"/>
<bean id="work" class="com.ctbu.xmlconfigtest.domain.Work" c:person-ref="person"/>
</beans>
使用位置标志
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person"/>
<bean id="work" class="com.ctbu.xmlconfigtest.domain.Work" c:_0-ref="person"/>
</beans>
当构造器只有一个参数的时候,可以直接使用下划线(这种方式在IDEA集成环境下会报错,但是并不影响使用,这是集成环境的检查机制)所以选择一个最合适的即可
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person"/>
<bean id="work" class="com.ctbu.xmlconfigtest.domain.Work" c:_-ref="person"/>
</beans>
构造器中注入字面量值
使用xml元素注入(此时的constructor-arg后不再用ref进行引用,而直接是value属性)
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<constructor-arg value="李白"/>
</bean>
</beans>
使用c-命名空间
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person" c:name="李白"/>
</beans>
构造器装配集合
这种装配在XML中只有<constructor-arg/>属性能办到
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<constructor-arg>
<list>
<value>篮球</value>
<value>足球</value>
<value>游戏</value>
</list>
</constructor-arg>
</bean>
</beans>
这里person对象的构造器需要一个string数据类型的数据,同样的如果实际上你需要的是一个其他对象类型的引用,你可以把value改成ref即可完成bean引用列表的装配。
对于集合类型的变化也可以自行选择,使用list还是set,他们的差别和Java语法中,list和set集合的差别是一样的。
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<constructor-arg>
<set>
<value>篮球</value>
<value>足球</value>
<value>游戏</value>
</set>
</constructor-arg>
</bean>
</beans>
XML中属性值的注入
属性值的注入方式也有2种,都需要提供属性的setter方法
- XML元素注入
- p命名空间注入
字面量属性注入——XML元素
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<property name="name" value="李白"/>
</bean>
</beans>
p-命名空间的方式
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person" p:name="李白"/>
</beans>
若属性值为对象引用,同样使用ref的方式进行引用
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<property name="work" ref="work"/>
</bean>
<bean id="work" class="com.ctbu.xmlconfigtest.domain.Work"/>
</beans>
属性中集合的装配
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<property name="hobby">
<list>
<value>唱</value>
<value>鬼畜</value>
</list>
</property>
</bean>
</beans>
使用util命名空间完成属性集合的装配,如果使用util命名空间则需要在头部引入util命名空间规范。
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
<property name="hobby" ref="hobby"/>
</bean>
<util:list id="hobby">
<value>唱</value>
<value>跳</value>
<value>rap</value>
</util:list>
</beans>