Bean的基础配置
装配机制
Spring提供了三种装配机制:
- 自动化装配
- Java代码装配
- XML装配
自动化装配bean
Spring从两个角度来实现自动化装配:
- 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
- 自动装配(autowiring):Spring自动满足bean之间的依赖。
Spring装配bean首先需要知道装配那些bean,即范围和标志,所以需要组件扫描Spring上下文中需要创建bean的标志。
Spring通过@ComponentScan注解启动扫描,@ComponentScan有一个属性basePackages可以设置要扫描的基础包,注意基础包路径为全路径,当然可能你注意到了basePackages是一个复数,所以可以配置多个基础包,若只配置一个基础包,可以省略basePackages;若不配置基础包,那么扫描的是配置类当前的包以及其子包。
@Configuration
@ComponentScan( "com.cxd.javaweb.service")
public class ComponentConfig {
}
或者
@Configuration
@ComponentScan(basePackages = "com.cxd.javaweb.service")
public class ComponentConfig {
}
或者
@Configuration
@ComponentScan(basePackages = {"com.cxd.javaweb.service","com.cxd.javaweb.bussiness"})
public class ComponentConfig {
}
@Configuration注解是表示这个类是配置类
若扫描的不是包,也可以扫描具体的类可以使用注解@ComponentScan的另外一个属性basePackageClasses,用法与basePackages类似
现在使用注解@Configuration创建了配置类,使用@ComponentScan启动自动扫描了,那么创建bean的标志是什么呢?
@Component注解就可以作为类创建bean的标识,如:
@Component
public class HuaweiComputer implements IComputer {
public String getName(){
return "Huawei";
}
}
Spring应用上下文中所有bean都有一个ID,默认bean的ID是类名首字母小写,如上类HuaweiComputer的ID为huaweiComputer,但是@Component可以设置bean的ID,使用属性value,如:
//注解@Component的value属性可以省略
@Component("LenovoPc")
public class LenovoComputer implements IComputer {
public String getName() {
return "Lenovo";
}
}
简单的说,自动装配就是融Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean,为了声明要进行自动装配我们需要借助一些注解,比如@Autowired,@Resource。
测试自动装配
@Configuration
@ComponentScan(basePackages = {"com.cxd.javaweb.service"} )
public class ComponentConfig {
}
public interface IComputer {
public String getName();
}
@Component("LenovoPc")
public class LenovoComputer implements IComputer {
public String getName() {
return "Lenovo";
}
}
//@ContextConfiguration加载配置类,使用属性classes
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ComponentConfig.class)
public class ComputerTest {
@Autowired
@Qualifier("LenovoPc")
private IComputer iComputer;
@Test
public void testName(){
String name = iComputer.getName();
System.out.println(name);
}
}
结果:Lenovo
1、 @Component是基础注解,还有 @Controller,@RestController,@Service,@Repository 这些注解为了程序的可读性,以及不同层次使用的与@Component作用相同
@Controller和@RestController用于视图层,常作用于接口
@Service用于业务层
@Repository用于数据访问层
注意:@RestController和@Controller的区别
@RestController是ResponseBody + Controller,使用@RestController返回的是对象
@Controller可以与视图解析器InternalResourceViewResolver配合使用返回页面
2、自动装配bean的注解有:@Autowired,@Resource
注意:常比较的是@Autowired与@Resource
(1)@Autowired是Spring的注解,@Resource是JSR-250Java规范注解
(2)@Autowired按byType自动注入,而@Resource默认按 byName自动注入,@Autowired可以与@Qualifier配合使用实现通过name自动注入
(3)@Resource装配顺序
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
建议使用@Resource
JAVA代码装配bean
尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化装配是更为推荐的方式,但是有时候自动化配置的方案行不通,因此需要明确配置Spring。比如:你想要将第三方库中的组件装配到你的应用中,就不能使用@Component和@Autowired注解了。
首先需要创建配置类,声明简单的bean,如下:
@Configuration
public class SqlfxConfiguration {
@Bean(name = "sqlfxClient",initMethod="init")
public ClientMain sqlfx(){
return new ClientMain();
}
}
以上实例是公司添加sql分析需要配置的bean,其中ClientMain是第三方jar包
@Configuration注解标识该类为配置类
@Bean注解告诉Spring这个方法将返回一个对象,该对象要注册为Spring应用上下文中的bean。bean的ID与带有@Bean注解的方法名一样,但是我们可以通过@Bean的一些属性改变其默认值,比如通过name属性改变bean的ID,如上面的例子,该bean的ID为“sqlxClient”,也可以使用属性value。
@Bean注解中initMethod属性表示初始化后要执行ClientMain类中的init()方法,还有一个属性destroyMethod表示bean销毁前要执行的方法
小知识:spring中若某个类中的某个方法需要在项目启动的时候执行,那么该类可以实现InitializingBean接口,重写afterPropertiesSet()方法,通过这个方法调用要执行的那个方法。
当然创建bean的方式不一定都是使用new的方式,如下:
@Configuration
public class CacheConfiguration {
@Bean(name = "RcpEhCacheManager")
public CacheManager ehCacheManager() throws CacheException, IOException {
return CacheManager.newInstance(new ClassPathResource(
"/cache/caseEhcache.xml").getInputStream());
}
}
此实例是配置Ehcache缓存的方法,需要读取xml文件,使用newInstance创建CacheManager对象。
XML装配bean
xml装配bean的方式是Spring最早的装配bean 的方案,但是随着自动装配方式和Java代码装配方式的出现,xml装配方式逐渐被人们弃用了,但是我们可以通过学习xml配置能很好的理解自动装配和Java代码装配的原理,所以还是要了解的。
在使用JavaConfig的时候,需要创建一个带有@Configuration注解的类,而在xml配置中需要创建一个xml文件,并且要以**<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.cxd.javaweb.bean.DellComputer" id="dellComputer"></bean>
</beans>
bean的属性:
id:唯一标识,ioc容器中的Bean的key值,从ioc容器中获取一个实例的时候,需要通过id来获取
name:可以通过name从容器中获取Bean,Bean的别名,有id的情况下,id为Bean的key,没有id的情况下,name为实例的key
class:将哪一个类进行实例化,写的是类的完全限定名(包名+类名)
使用反射对一个类进行实例化,如果写错了,在反射时会报ClassNotFoundException
lazy-init:延迟初始化,默认是在容器启动的时候就进行加载,true是延迟加载,什么时候从容器中获取该Bean什么时候才实例化,只有在单例模式下生效
parent:指定该类的父类,将会继承父类实例化后的所有属性,实例化该类的时候,会先触发父类的实例化,在该类进行实例化时,可以覆盖继承父类中某个属性的值,要求该类与父类是同一个类型(继承),当然首先要将父类装入容器中,parent写的是父类Bean的id
abstract:不会在容器中创建该类的实例,如果从容器中获取,会报错
depend-on:依赖检查,要实例化A类,但是实例化A类需要依赖B类,首先要保证B类已经实例化过了,B类的id。指定该Bean在实例化的时候依赖Bean,所依赖的Bean会将该Bean实例化之前进行实例化。depend-on写的某个Bean的id
init-method:初始化方法,该Bean在实例化时会自动调用一个方法,该方法必须是无参的,直接写方法名,不写小括号,只在单例模式下生效
destroy-method:容器关闭时调用的方法,该方法必须是无参的,且只有单例模式下才能生效。调动ctx.close()就是关闭容器
构造器初始化bean
构造器初始化bean有两种方案:
- <constructor-arg>元素
- 使用Spring3.0所引入的c-命名空间
Java代码中构造函数如下:
public class Computer {
private DellComputer dellComputer;
public Computer(DellComputer dellComputer){
this.dellComputer = dellComputer;
}
public String getName(){
return dellComputer.getName();
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.cxd.javaweb.bean.DellComputer" id="dellComputer">
</bean>
<bean class="com.cxd.javaweb.service.Computer" id="computer">
<constructor-arg ref="dellComputer"/>
</bean>
</beans>
测试类如下:
//@ContextConfiguration加载配置文件,使用属性locations
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:/spring-bean.xml")
public class XmlConfigTest {
@Resource
private DellComputer dellComputer;
@Test
public void testDell(){
String name = dellComputer.getName();
System.out.println(name);
}
}
或者
@RunWith(SpringJUnit4ClassRunner.class)
public class XmlConfigTest {
@Test
public void testDellName(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-bean.xml");
Computer dellComputer = (Computer)applicationContext.getBean("computer");
String name = dellComputer.getName();
System.out.println(name);
}
}
结果:dell
装配集合
集合有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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.cxd.javaweb.service.Computer" id="computer">
<constructor-arg>
<list>
<ref bean="huaweiComputer">
<ref bean="levonoComputer">
<ref bean="dellComputer">
</list>
</constructor-arg>
</bean>
</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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.cxd.javaweb.service.Computer" id="computer">
<constructor-arg>
<list>
<value>品牌名:华为</value>
<value>品牌名:联想</value>
<value>品牌名:戴尔</value>
</list>
</constructor-arg>
</bean>
</beans>
属性赋值
设置属性用<property>元素为属性的setter方法所提供的功能与<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 class="com.cxd.javaweb.bean.DellComputer" id="dellComputer">
</bean>
<bean class="com.cxd.javaweb.service.Computer" id="computer">
<constructor-arg ref="dellComputer"/>
<property name="cname" value="电脑"/>
<property name="colour" value="黑色"/>
</bean>
</beans>