spring配置bean

spring配置bean

使用xml配置

使用构造器创建

构造器创建bean是最常用的,如果不使用构造注入,Spring会调用无参构造器来创建实例

使用的是反射机制,要求该bean所对应的类必须有一个无参构造器

而对于注入方式,有构造器注入和setter方法注入

依赖注入方式
setter方法注入

使用setter方法注入时,注意一定要有无参构造器,spring会根据配置的class来使用class.newInstance()方法来实例化该bean

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 配置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值设置

xml 复制代码
<bean id="helloWorld" class="com.zhanghe.study.spring4.beans.helloworld.HelloWorld">
        <property name="name">
            <null/>
        </property>
    </bean>

注入不同的类型

  • 简单类型使用value

    xml 复制代码
    <property name="name" value="Spring Hello"/>
  • 引用类型使用ref

    xml 复制代码
    <property name="car" ref="car2"/>
  • 集合类型list

    xml 复制代码
    <property name="cars">
        <list>
            <ref bean="car"/>
            <ref bean="car2"/>
        </list>
    </property>
  • 集合类型set

    xml 复制代码
    <property name="cars">
        <set>
            <ref bean="car"/>
            <ref bean="car2"/>
        </set>
    </property>
  • 集合类型map

    xml 复制代码
    <property name="carMap">
        <map>
            <entry key="AA" value-ref="car"/>
            <entry key="BB" value-ref="car2"/>
        </map>
    </property>
  • 集合类型 properties

    xml 复制代码
    <property name="testProp">
        <props>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
        </props>
    </property>
构造方法注入
xml 复制代码
<!-- 
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

java 复制代码
// 创建spring的IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 从IOC容器获取HelloWorld  bean实例
HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
配置bean引用

如果bean之间有引用关系,可以使用ref来指定引用关系

java 复制代码
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值

xml 复制代码
<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>
配置集合属性

可以使用、、来对集合属性赋值

xml 复制代码
<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的方式,可以进行配置集合属性

xml 复制代码
<!-- 配置集合bean -->
<util:list id="cars">
  <ref bean="car"/>
  <ref bean="car2"/>
</util:list>

然后在需要使用集合的bean中直接引用该集合bean

xml 复制代码
<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的工厂

java 复制代码
/**
 * 实现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对象

xml 复制代码
<bean id="c" class="com.zhanghe.study.spring4.beans.beantest.CarFactoryBean"></bean>

使用静态工厂方法创建Bean

使用静态工厂方法创建bean实例时,class属性也必须指定,此时的class属性并不是指定Bean实例的实现类,而是静态工厂类,Spring通过该属性知道由哪个工厂类来创建Bean实例,还可以使用factory-method属性来指定静态工厂方法,Spring将调用静态工厂方法返回一个Bean实例,静态工厂方法需要参数的话,使用元素指定

java 复制代码
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);
    }
}
xml 复制代码
<!-- 通过静态工厂方法来配置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指定工厂实例

java 复制代码
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);
    }
}
xml 复制代码
<!-- 配置工厂实例 -->
<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属性来配置

xml 复制代码
<!-- 自动装配 -->
<!-- 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为首选项

xml 复制代码
<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="包名"/>

使用注解进行配置

使用注解进行配置时要先开启组件扫描

xml 复制代码
<!-- 开启组件扫描 设置包扫描路径,如果扫描多个包,使用,隔开 -->
<context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest">
</context:component-scan>

还可以自定义的设置对于该包下的某些组件是否进行扫描

在使用<context:component=scan base-package="包名"/>标签时,记得要加上context的命名空间

设置过滤

使用context:exclude-filter来设置排除哪些特定的组件

xml 复制代码
<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来设置只扫描哪些特定的组件

xml 复制代码
<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

    java 复制代码
    @Autowired
    @Qualifier("bpmServiceImpl")
    private BpmService bpmService;
  • 使用@Inject和@Named结合来指定

    java 复制代码
    @Inject
    @Named("compensateServiceImpl")
    private CompensateService compensateService;
歧义性处理

在自动装配时有时会遇到该接口有多个不同的实现类,此时spring不知道选择哪个来进行注入,就会出现NoUniqueBeanDefinitionException异常,可以使用@Primary来标注其中一个可选bean为首选项,也可以使用@Qualifier注解来选择注入哪个bean的id

zhhll.icu/2021/框架/spr...

本文由mdnice多平台发布

相关推荐
陈小桔1 小时前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!1 小时前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg36781 小时前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July1 小时前
Hikari连接池
java
微风粼粼2 小时前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse
番茄Salad2 小时前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud
天若有情6732 小时前
Spring MVC文件上传与下载全面详解:从原理到实战
java·spring·mvc·springmvc·javaee·multipart
祈祷苍天赐我java之术2 小时前
Redis 数据类型与使用场景
java·开发语言·前端·redis·分布式·spring·bootstrap
Olrookie3 小时前
若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
java·前端·笔记·后端·学习·vue·ruoyi
倚栏听风雨4 小时前
java.lang.SecurityException异常
java