文章目录
spring配置bean
使用xml配置
使用构造器创建
构造器创建bean是最常用的,如果不使用构造注入,Spring会调用无参构造器来创建实例
使用的是反射机制,要求该bean所对应的类必须有一个无参构造器
而对于注入方式,有构造器注入和setter方法注入
依赖注入方式
setter方法注入
使用setter方法注入时,注意一定要有无参构造器,spring会根据配置的class来使用class.newInstance()方法来实例化该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 配置bean的全类名,使用反射的方式创建bean,要求必须有一个无参构造器
id 标识容器z中的bean id唯一
-->
<bean id="helloWorld" class="com.zhanghe.study.spring4.beans.helloworld.HelloWorld">
<property name="name" value="Spring Hello"/>
</bean>
</beans>
注意:bean配置的property属性的name值表示的是setter风格的属性,即setter方法去掉set之后首字母小写的名称,并不是和成员变量进行对应
null值设置
<bean id="helloWorld" class="com.zhanghe.study.spring4.beans.helloworld.HelloWorld">
<property name="name">
<null/>
</property>
</bean>
注入不同的类型
-
简单类型使用value
<property name="name" value="Spring Hello"/>
-
引用类型使用ref
<property name="car" ref="car2"/>
-
集合类型list
<property name="cars"> <list> <ref bean="car"/> <ref bean="car2"/> </list> </property>
-
集合类型set
<property name="cars"> <set> <ref bean="car"/> <ref bean="car2"/> </set> </property>
-
集合类型map
<property name="carMap"> <map> <entry key="AA" value-ref="car"/> <entry key="BB" value-ref="car2"/> </map> </property>
-
集合类型 properties
<property name="testProp"> <props> <prop key="username">root</prop> <prop key="password">123456</prop> </props> </property>
构造方法注入
<!--
constructor-arg
value为属性值
index 表示对应构造器的参数位置 从0开始
type 表示构造器该参数的类型
ref 如果入参是bean
-->
<bean id="car" class="com.zhanghe.study.spring4.beans.beantest.Car">
<constructor-arg value="法拉利" index="0"/>
<constructor-arg value="20000.0" type="double"/>
</bean>
获取bean
// 创建spring的IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 从IOC容器获取HelloWorld bean实例
HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
配置bean引用
如果bean之间有引用关系,可以使用ref来指定引用关系
public class Person {
private String name;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", car=" + car +
'}';
}
}
这里的ref中写的是其他bean的id值
<bean id="car" class="com.zhanghe.study.spring4.beans.beantest.Car">
<constructor-arg value="法拉利" index="0"/>
<constructor-arg value="20000.0" type="double"/>
</bean>
<bean id="person" class="com.zhanghe.study.spring4.beans.beantest.Person">
<property name="name" value="张三"/>
<property name="car" ref="car"/>
</bean>
配置集合属性
可以使用、、
<bean id="person" class="com.zhanghe.study.spring4.beans.beantest.Person">
<property name="name" value="张三"/>
<property name="car" ref="car"/>
<property name="cars">
<!-- list的示例 -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
</list>
</property>
<property name="carMap">
<!-- map的示例 entry可以使用key/key-ref/value/value-ref -->
<map>
<entry key="AA" value-ref="car"/>
<entry key="BB" value-ref="car2"/>
</map>
</property>
</bean>
还有一种集合bean的方式,可以进行配置集合属性
<!-- 配置集合bean -->
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
然后在需要使用集合的bean中直接引用该集合bean
<bean id="person1" class="com.zhanghe.study.spring4.beans.beantest.Person">
<property name="name" value="张三"/>
<property name="car" ref="car"/>
<!-- 引用上述定义的集合bean -->
<property name="cars" ref="cars"/>
</bean>
使用工厂bean来创建实际bean
对于某些对象的实例化过程特别的繁琐,更希望使用java代码来完成实例化过程,可以提供一个实现FactoryBean接口的工厂bean来生产所实际需要的bean对象
请区分开FactoryBean和BeanFactory,FactoryBean本身来说是一个bean,而BeanFactory确是Bean的工厂
/**
* 实现FactoryBean接口来生成car对象
* @author zh
* @date 2021/1/30 16:01
*/
public class CarFactoryBean implements FactoryBean<Car> {
/**
* 真正获取对象的方法
* @return
* @throws Exception
*/
@Override
public Car getObject() throws Exception {
return new Car("玛莎拉蒂",300);
}
/**
* 生成bean的类型
* @return
*/
@Override
public Class<?> getObjectType() {
return Car.class;
}
/**
* 是否是单例
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
使用该factoryBean对象时,由于该bean实现了FactoryBean,所以spring不会把它作为一个普通的bean来处理,而是作为一个工厂bean,调用getObject()方法来创建实际需要的bean对象
<bean id="c" class="com.zhanghe.study.spring4.beans.beantest.CarFactoryBean"></bean>
使用静态工厂方法创建Bean
使用静态工厂方法创建bean实例时,class属性也必须指定,此时的class属性并不是指定Bean实例的实现类,而是静态工厂类,Spring通过该属性知道由哪个工厂类来创建Bean实例,还可以使用factory-method属性来指定静态工厂方法,Spring将调用静态工厂方法返回一个Bean实例,静态工厂方法需要参数的话,使用元素指定
public class StaticCarFactory {
private static Map<String,Car> cars = new HashMap<>();
static {
cars.put("aa",new Car("aa",300));
}
public static Car getCar(String name){
return cars.get(name);
}
}
<!-- 通过静态工厂方法来配置bean
class 静态工厂类
factory-method 静态工厂方法的名字
constructor-arg 指定静态方法的参数
-->
<bean id="car" class="com.zhanghe.study.spring4.beans.beantest.StaticCarFactory"
factory-method="getCar">
<constructor-arg name="name" value="aa" index="0"/>
</bean>
优点:将对象创建的过程封装到静态方法中,当客户端需要对象时,只需要简单地调用静态方法,不需要关系创建对象的细节
调用实例工厂方法创建bean
实例工厂与静态工厂只有一个不同,静态工厂只需要使用工厂类即可,实例工厂需要工厂实例,使用factory-bean指定工厂实例
public class InstanceCarFactory {
private Map<String,Car> cars = null;
public InstanceCarFactory(){
cars = new HashMap<>();
cars.put("bb",new Car("bb", 30000.0));
}
public Car getCar(String name){
return cars.get(name);
}
}
<!-- 配置工厂实例 -->
<bean id="instanceCarFactory" class="com.zhanghe.study.spring4.beans.beantest.InstanceCarFactory"/>
<!-- 通过实例工厂方法来配置bean
factory-bean 实例工厂的bean
factory-method 实例工厂方法的名字
constructor-arg 指定方法的参数
-->
<bean id="car1" factory-bean="instanceCarFactory" factory-method="getCar">
<constructor-arg name="name" value="bb" index="0"/>
</bean>
自动装配
上述的操作方式全是手动地进行注入的,如何进行自动装配呢,可以使用autowire属性来配置
<!-- 自动装配 -->
<!-- byName 根据属性名称去匹配到对应的bean
byType 根据属性的类型去匹配到对应的bean
-->
<bean id="testAutoWired" class="com.zhanghe.study.spring4.beans.beantest.Person" autowire="byName">
<property name="name" value="张三"/>
</bean>
如果使用byType,而且存在多个该类型的bean的话,就会出现异常
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.zhanghe.study.spring4.beans.beantest.Car’ available: expected single matching bean but found 2: car,car2
歧义性处理
在自动装配时有时会遇到该接口有多个不同的实现类,此时spring不知道选择哪个来进行注入,就会出现NoUniqueBeanDefinitionException异常
可以使用primary来设置其中一个可选bean为首选项
<bean id="car" class="com.zhanghe.study.spring4.beans.beantest.Car" primary="true">
使用注解配置
spring可以在classpath下进行组件扫描,包含注解有
- @Component 基本注解,表示是一个受spring管理的组件
- @Respository 表示持久层组件
- @Service 表示业务层组件
- @Controller 表示表现层组件
spring扫描到组件后,有默认的命名策略,将扫描到的类名进行首字母小写,也可以在注解中使用value属性值来标识组件的名称
如果使用注解来标识bean的话,需要进行配置指定spring扫描的包,会扫描base-package指定的包及其子包
<context:component=scan base-package=“包名”/>
使用注解进行配置
使用注解进行配置时要先开启组件扫描
<!-- 开启组件扫描 设置包扫描路径,如果扫描多个包,使用,隔开 -->
<context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest">
</context:component-scan>
还可以自定义的设置对于该包下的某些组件是否进行扫描
在使用<context:component=scan base-package=“包名”/>标签时,记得要加上context的命名空间
设置过滤
使用context:exclude-filter来设置排除哪些特定的组件
<context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest">
<!-- 使用context:exclude-filter来设置排除哪些特定的组件
type annotation表示使用注解的表达式
assignable保护指定具体bean的类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
设置包含
使用context:include-filter来设置只扫描哪些特定的组件
<context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest" use-default-filters="false">
<!-- 使用context:include-filter来设置只扫描哪些特定的组件,如果使用include-filter的话需要设置use-default-filters="false" -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
自动装配
使用xml进行自动装配的时候略显笨拙,而且使用起来也并不顺心,因为autowire只能选择byName或者byType,如果存在多个相同类型的bean使用byType就会出现问题,大家可能因此想要放弃自动装配,其实自动装配与注解搭配起来还是很好用的,下面来了解一下
如果bean与bean之间存在关联关系,如在beanA中需要调用beanB的方法,如何来获取beanB中的实例呢?
<context:component-scan>元素会自动注册AutowiredAnnotationBeanPostProcessor实例和CommonAnnotationBeanPostProcessor实例,AutowiredAnnotationBeanPostProcessor实例可以自动装配具有@AutoWired注解的属性,CommonAnnotationBeanPostProcessor实例可以自动装配@Resource注解的属性
在基于注解方式实现属性注入时主要使用的四个注解
-
@Autowired默认使用byType,如果存在类型相同的两个bean,则使用byName来根据属性的名称来匹配bean,默认情况下该依赖对象必须存在,如果允许不存在,需要配置@Autowired(required = false)
-
@Qualifier 根据属性名称进行注入byName,需要和@Autowired一起使用,使其按照类型的基础上按照name进行注入,给字段注入时不可独立使用,必须要和@Autowired一起使用;但是给方法参数注入时,可以独立使用
-
@Resource注解可以根据类型注入,也可以根据名称注入,若使用的byName,需要提供bean的名称,如果不提供该bean的名称,则自动使用属性的名称进行匹配
-
@Inject与@AutoWired一样,只是没有required属性
使用方式
-
使用@Autowired 和@Qualifier结合来明确指定需要装配的Bean
@Autowired @Qualifier("bpmServiceImpl") private BpmService bpmService;
-
使用@Inject和@Named结合来指定
@Inject @Named("compensateServiceImpl") private CompensateService compensateService;
歧义性处理
在自动装配时有时会遇到该接口有多个不同的实现类,此时spring不知道选择哪个来进行注入,就会出现NoUniqueBeanDefinitionException异常,可以使用@Primary来标注其中一个可选bean为首选项,也可以使用@Qualifier注解来选择注入哪个bean的id
参考文献