spring配置bean

作者: 墨线宝 | 来源:发表于2021-02-22 15:54 被阅读0次

    原文链接http://zhhll.icu/2021/%E6%A1%86%E6%9E%B6/spring/spring%E9%85%8D%E7%BD%AEbean/

    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之后首字母小写的名称,并不是和成员变量进行对应

    构造方法注入
    <!-- 
        value为属性值
        index 表示对应构造器的参数位置  从0开始
        type 表示构造器该参数的类型
    -->
    <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>
    
    配置集合属性

    可以使用<list>、<set>、<map>来对集合属性赋值

    <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

    可以提供一个实现FactoryBean接口的工厂bean来生产所实际需要的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实例,静态工厂方法需要参数的话,使用<constructor-arg>元素指定

    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
             byName  根据属性的类型去匹配到对应的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可以在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的命名空间

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">

    设置过滤

    使用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实例,该实例可以自动装配具有@AutoWired、@Resource和@Inject注解的属性

    @Autowired默认使用byType,如果存在类型相同的两个bean,则使用byName来根据属性的名称来匹配bean

    @Resource注解是使用的byName,需要提供bean的名称,如果不提供该bean的名称,则自动使用属性的名称进行匹配

    @Inject与@AutoWired一样,只是没有required属性

    • 使用@Autowired 和@Qualifier结合来明确指定需要装配的Bean

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

      @Inject
      @Named("compensateServiceImpl")
      private CompensateService compensateService;
      

    由于本身的博客百度没有收录,博客地址http://zhhll.icu

    相关文章

      网友评论

        本文标题:spring配置bean

        本文链接:https://www.haomeiwen.com/subject/ochkfltx.html