基于@Bean修饰的方法参数的注入方式

目录
  • @Bean修饰的方法参数的注入
  • Bean的四种注入方式
    • 1、set注入
    • 2、构造器注入
    • 3、静态工厂注入
    • 4、实例工厂注入

@Bean修饰的方法参数的注入

方法参数默认注入方式为Autowired,即先根据类型匹配,若有多个在根据名称进行匹配。

1:复杂类型可以通过@Qualifier(value=“XXX”)限定

2:对于普通类型使用@Value(XXX)指定

@PropertySource("classpath:db.properties")
public class SpringConfiguration {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
    /**
     * 方法参数默认注入方式为Autowired: <br>
     * 1:复杂类型可以通过@Qualifier(value="dataSource")限定; <br>
     * 2:对于普通类型使用@Value指定; <br>
     */
    @Bean(name = "dataSource")
    public DataSource dataSource(@Value("${jdbc.driverClass}") String driverClassName,
        @Value("${jdbc.jdbcUrl}") String url, @Value("${jdbc.user}") String username,
        @Value("${jdbc.password}") String password) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate jdbcTemplate(@Qualifier(value = "dataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

Bean的四种注入方式

我使用下面两个类来进行注入的演示,这两个类分别是User和Car类:

Car类:

public class Car {
    // 只包含基本数据类型的属性
    private int speed;
    private double price;

    public Car() {
    }
    public Car(int speed, double price) {
        this.speed = speed;
        this.price = price;
    }

    public int getSpeed() {
        return speed;
    }
    public void setSpeed(int speed) {
        this.speed = speed;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Car{" +
                "speed=" + speed +
                ", price=" + price +
                '}';
    }
}

User类:

public class User {

    private String name;
    private int age;
    // 除了上面两个基本数据类型的属性,User还依赖Car
    private Car car;

    public User() {
    }
    public User(String name, int age, Car car) {
        this.name = name;
        this.age = age;
        this.car = car;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

1、set注入

有了上面两个类,就可以演示set注入了。需要注意一点,如果需要使用set注入,那么必须要为属性提供set方法,Spring容器就是通过调用bean的set方法为属性注入值的。而在xml文件中,使用set注入的方式就是通过property标签,如下所示:

<!-- 定义car这个bean,id为myCar -->
<bean id="myCar" class="cn.tewuyiang.pojo.Car">
    <!--
        为car的属性注入值,因为speed和price都是基本数据类型,所以使用value为属性设置值;
        注意,这里的name为speed和price,不是因为属性名就是speed和price,
        而是set方法分别为setSpeed和setPrice,名称是通过将set删除,然后将第一个字母变小写得出;
    -->
    <property name="speed" value="100"/>
    <property name="price" value="99999.9"/>
</bean>
<!-- 定义user这个bean -->
<bean id="user" class="cn.tewuyiang.pojo.User">
    <property name="name" value="aaa" />
    <property name="age" value="123" />
    <!-- car是引用类型,所以这里使用ref为其注入值,注入的就是上面定义的myCar
         基本数据类型或Java包装类型使用value,
         而引用类型使用ref,引用另外一个bean的id
    -->
    <property name="car" ref="myCar" />
</bean>

通过上面的配置,就可以为Car和User这两个类型的bean注入值了。需要注意的是,property的name属性,填写的不是属性的名称,而是set方法去除set,然后将第一个字符小写后的结果。对于基本数据类型,或者是Java的包装类型(比如String),使用value注入值,而对于引用类型,则使用ref,传入其他bean的id。接下来就可以测试效果了:

@Test
public void test1() {
    ApplicationContext context =
        new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    // 获取user这个bean
    User user = context.getBean(User.class);
    // 输出产看结果
    System.out.println(user);
}

由于user包含car的引用,所以直接输出user,也能够看到car的情况,输入结果如下:

User{name='aaa', age=123, car=Car{speed=100, price=99999.9}}

2、构造器注入

下面来说第二种方式——构造器注入。听名字就可以知道,这种注入值的方式,就是通过调用bean所属类的带参构造器为bean的属性注入值。这也就意味着,如果需要使用构造器注入,就得为类提供包含参数的构造方法。构造器注入,实际上有多种匹配属性值的方式,下面就来一一列举。这里依然使用定义的Car和User这两个类,测试方法以及类的定义都不需要变,需要改变的仅仅是xml配置文件。

(一)匹配构造器的参数名称

需要通过constructor-arg标签为构造器传入参数值,但是每个constructor-arg标签对应哪一个参数值呢?这就有多种方式指定了。第一种就是直接匹配参数名,配置如下:

<bean id="myCar" class="cn.tewuyiang.pojo.Car">
    <!-- 通过constructor-arg的name属性,指定构造器参数的名称,为参数赋值 -->
    <constructor-arg name="speed" value="100" />
    <constructor-arg name="price" value="99999.9"/>
</bean>
<bean id="user" class="cn.tewuyiang.pojo.User">
    <constructor-arg name="name" value="aaa" />
    <constructor-arg name="age" value="123" />
    <!--
         和之前一样,基本数据类型或Java包装类型使用value,
         而引用类型使用ref,引用另外一个bean的id
    -->
    <constructor-arg name="car" ref="myCar" />
</bean>

这样就完成了,测试代码和之前一样,运行结果也一样,这里的配置和set注入时的配置几乎一样,除了一个使用property,一个使用constructor-arg。写法上一样,但是表示的含义却完全不同。property的name属性,是通过set方法的名称得来;而constructor-arg的name,则是构造器参数的名称。

(二)匹配构造器的参数下标

上面是通过构造器参数的名称,匹配需要传入的值,那种方式最为直观,而Spring还提供另外两种方式匹配参数,这里就来说说通过参数在参数列表中的下标进行匹配的方式。下面的配置,请结合User和Car的构造方法一起阅读,配置方式如下:

<bean id="car" class="cn.tewuyiang.pojo.Car">
    <!-- 下标编号从0开始,构造器的第一个参数是speed,为它赋值100 -->
    <constructor-arg index="0" value="100" />
    <!-- 构造器的第二个参数是price,为它赋值99999.9 -->
    <constructor-arg index="1" value="99999.9"/>
</bean>
<bean id="user" class="cn.tewuyiang.pojo.User">
    <!-- 与上面car的配置同理 -->
    <constructor-arg index="0" value="aaa" />
    <constructor-arg index="1" value="123" />
    <constructor-arg index="2" ref="car" />
</bean>

上面就是通过参数的下标为构造器的参数赋值,需要注意的是,参实的下标从0开始。使用上面的方式配置,若赋值的类型与参数的类型不一致,将会在容器初始化bean的时候抛出异常。如果bean存在多个参数数量一样的构造器,Spring容器会自动找到类型匹配的那个进行调用。比如说,Car有如下两个构造器,Spring容器将会调用第二个,因为上面的配置中,index = 1对应的value是double类型,与第二个构造器匹配,而第一个不匹配:

public Car(double price, int speed) {
    this.speed = speed;
    this.price = price;
}
// 将使用匹配这个构造器
public Car(int speed, double price) {
    this.speed = speed;
    this.price = price;
}

还存在另外一种特殊情况,那就是多个构造器都满足bean的配置,此时选择哪一个?假设当前car的配置是这样的:

<bean id="car" class="cn.tewuyiang.pojo.Car">
    <!-- 两个下标的value值都是整数 -->
    <constructor-arg index="0" value="100" />
    <constructor-arg index="1" value="999"/>
</bean>

假设Car还是有上面两个构造器,两个构造器都是一个int类型一个double类型的参数,只是位置不同。而配置中,指定的两个值都是int类型。但是,int类型也可以使用double类型存储,所以上面两个构造器都是匹配的,此时调用哪一个呢?结论就是调用第二个。自己去尝试就会发现,若存在多个构造器匹配bean的定义,Spring容器总是使用最后一个满足条件的构造器。

(三)匹配构造器的参数类型

下面说最后一种匹配方式——匹配构造器的参数类型。直接看配置文件吧:

<bean id="car" class="cn.tewuyiang.pojo.Car">
    <!-- 使用type属性匹配类型,car的构造器包含两个参数,一个是int类型,一个是double类型 -->
    <constructor-arg type="int" value="100" />
    <constructor-arg type="double" value="99999.9"/>
</bean>
<bean id="user" class="cn.tewuyiang.pojo.User">
    <!-- 对于引用类型,需要使用限定类名 -->
    <constructor-arg type="java.lang.String" value="aaa" />
    <constructor-arg type="int" value="123" />
    <constructor-arg type="cn.tewuyiang.pojo.Car" ref="car" />
</bean>

上面应该不难理解,直接通过匹配构造器的参数类型,从而选择一个能够完全匹配的构造器,调用这个构造器完成bean的创建和属性注入。需要注意的是,上面的配置中,类型并不需要按构造器中声明的顺序编写,Spring也能进行匹配。这也就意味着可能出现多个能够匹配的构造器,和上一个例子中一样。比如说,Car还是有下面两个构造器:

public Car(double price, int speed) {
    // 输出一句话,看是否调用这个构造器
    System.out.println(111);
    this.speed = speed;
    this.price = price;
}
// 将使用匹配这个构造器
public Car(int speed, double price) {
    // 输出一句话,看是否调用这个构造器
    System.out.println(222);
    this.speed = speed;
    this.price = price;
}

上面两个构造器都是一个int,一个double类型的参数,都符合xml文件中,car这个bean的配置。通过测试发现,Spring容器使用的永远都是最后一个符合条件的构造器,这和上面通过下标匹配是一致的。需要说明的一点是,这三种使用构造器注入的方式,可以混用。

3、静态工厂注入

静态工厂注入就是编写一个静态的工厂方法,这个工厂方法会返回一个需要的值,然后在配置文件中,指定使用这个工厂方法创建bean。首先需要一个静态工厂,如下所示:

public class SimpleFactory {
    /**
     * 静态工厂,返回一个Car的实例对象
     */
    public static Car getCar() {
        return new Car(12345, 5.4321);
    }
}

下面需要在xml中配置car这个bean,并指定它由工厂方法进行创建。配置如下:

<!--
 注意,这里的配置并不是创建一个SimpleFactory对象,取名为myCar,
    这一句配置的意思是,调用SimpleFactory的getCar方法,创建一个car实例对象,
    将这个car对象取名为myCar。
-->
<bean id="car" class="cn.tewuyiang.factory.SimpleFactory" factory-method="getCar"/>
<bean id="user" class="cn.tewuyiang.pojo.User">
    <!-- name和age使用set注入 -->
    <property name="name" value="aaa"/>
    <property name="age" value="123"/>
    <!-- 将上面配置的car,注入到user的car属性中 -->
    <property name="car" ref="car"/>
</bean>

以上就配置成功了,测试方法以及执行效果如下,注意看car的属性值,就是在静态工厂中配置的那样,这说明,Spring容器确实是使用定义的静态工厂方法,创建了car这个bean:

@Test
public void test1() {
    ApplicationContext context =
        new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    // 获取静态工厂创建的car
    Car car = (Car) context.getBean("car");
    // 获取user
    User user = context.getBean(User.class);
    System.out.println(car);
    System.out.println(user);
}

输出如下所示:

Car{speed=12345, price=5.4321}

User{name='aaa', age=123, car=Car{speed=12345, price=5.4321}}

4、实例工厂注入

实例工厂与静态工厂类似,不同的是,静态工厂调用工厂方法不需要先创建工厂类的对象,因为静态方法可以直接通过类调用,所以在上面的配置文件中,并没有声明工厂类的bean。但是,实例工厂,需要有一个实例对象,才能调用它的工厂方法。先看看实例工厂的定义:

public class SimpleFactory {
    /**
     * 实例工厂方法,返回一个Car的实例对象
     */
    public Car getCar() {
        return new Car(12345, 5.4321);
    }
    /**
     * 实例工厂方法,返回一个String
     */
    public String getName() {
        return "tewuyiang";
    }
    /**
     * 实例工厂方法,返回一个int,在Spring容器中会被包装成Integer
     */
    public int getAge() {
        return 128;
    }
}

在上面的工厂类中,共定义了三个工厂方法,分别用来返回user所需的car,name以及age,而配置文件如下:

<!-- 声明实例工厂bean,Spring容器需要先创建一个SimpleFactory对象,才能调用工厂方法 -->
<bean id="factory" class="cn.tewuyiang.factory.SimpleFactory" />
<!--
    通过实例工厂的工厂方法,创建三个bean,通过factory-bean指定工厂对象,
    通过factory-method指定需要调用的工厂方法
-->
<bean id="name" factory-bean="factory" factory-method="getName" />
<bean id="age" factory-bean="factory" factory-method="getAge" />
<bean id="car" factory-bean="factory" factory-method="getCar" />
<bean id="user" class="cn.tewuyiang.pojo.User">
    <!-- 将上面通过实例工厂方法创建的bean,注入到user中 -->
    <property name="name" ref="name"/>
    <property name="age" ref="age"/>
    <property name="car" ref="car"/>
</bean>

尝试从Spring容器中取出name,age,car以及user,看看它们的值,测试代码如下:

@Test
public void test1() {
    ApplicationContext context =
        new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    // 获取静态工厂创建的car,name和age这三个bean
    Car car = (Car) context.getBean("car");
    String name = (String) context.getBean("name");
    Integer age = (Integer) context.getBean("age");
    // 获取user这个bean
    User user = context.getBean(User.class);
    System.out.println(car);
    System.out.println(name);
    System.out.println(age);
    System.out.println(user);
}

以下就是输出结果,可以看到,通过工厂创建的bean,都在Spring容器中能够获取到:

Car{speed=12345, price=5.4321}

tewuyiang

128

User{name='tewuyiang', age=128, car=Car{speed=12345, price=5.4321}}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解Spring中bean的几种注入方式

    首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring容器中支持的依赖注入方式主要有属性注入.构造函数注入.工厂方法注入.接下来将为大家详细介绍这三种依赖注入的方式以及它们的具体配置方法. 1.属性注入 属性注入即通过setXXX( )方法注入bean的属性值或依赖对象.由于属性注入方式具有可选择性和灵活性高的特点,因此它也是实际开发中最常用的注入方式

  • Spring Bean三种注入方式详解

    在Spring容器中为一个bean配置依赖注入有三种方式: 使用属性的setter方法注入  这是最常用的方式: 使用构造器注入: 使用Filed注入(用于注解方式). Field注入是最常见的一种方式,可以采用 @Autowired 对Bean类的接口进行初始化,代码如下 @ContextConfiguration({"/META-INF/spring/amazing-base.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public

  • Spring注入值到Bean的三种方式

    在Spring中,有三种方式注入值到 bean 属性. 正常的方式 快捷方式 "p" 模式 新建一个User类,它包含username和password两个属性,现在使用spring的IOC注入值到该bean. package com.example.pojo; public class User { private String username; private String password; public String getUsername() { return userna

  • Spring Bean的属性注入方式

    在spring中bean的属性注入有两种 构造器注入 <bean id="car" class="nwtxxb.di.Car"> <constructor-arg index="0" type="java.lang.String" value="保时捷"></constructor-arg> <constructor-arg index="1"

  • 基于@Bean修饰的方法参数的注入方式

    目录 @Bean修饰的方法参数的注入 Bean的四种注入方式 1.set注入 2.构造器注入 3.静态工厂注入 4.实例工厂注入 @Bean修饰的方法参数的注入 方法参数默认注入方式为Autowired,即先根据类型匹配,若有多个在根据名称进行匹配. 1:复杂类型可以通过@Qualifier(value="XXX")限定 2:对于普通类型使用@Value(XXX)指定 @PropertySource("classpath:db.properties") public

  • 基于Spring p标签和c标签注入方式

    目录 Spring p和c标签注入方式 1.编写实体类 2.配置文件(重点) 3.测试 spring Bean注入和P标签使用 1.构造方法参数 2.setter方法注入(开发推荐) 3.p名称空间的使用 4.集合类型的属性注入(了解) Spring p和c标签注入方式 1.编写实体类 package com.ming04.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstru

  • 普通类注入不进spring bean的解决方法

    解决问题:我在做移动端accessToken的使用遇到一个问题,就是普通类死活注入不进去spring bean,我和同事雷杰通过各种注解,xml配置搞了好久都搞不定,这里插个眼,有空补一下spring,得深入研究一下 解决办法:后面通过一个spring工具类搞定,这里贴上代码 1.引入这个springUtil类 2.通过构造方法注入 贴上SpringUtils代码: package com.dt.base.weixin.util; import org.springframework.aop.f

  • Spring IOC容器的Bean管理基于注解属性注入方式

    目录 基于注解方式进行属性注入 一.@Autowired 1. 添加对象注解 2. 在service中注入dao对象 3. 创建测试函数测试效果 二.@Qualifier 三.@Resource 1. 替代 @Autowired 2. 替换 @Qualifier 四.@Value 基于注解方式进行属性注入 涉及到 4 个注解 @Autowired:根据属性类型,进行自动装配 @Qualifier:根据属性名称进行注入,跟 @Autowired 一起使用 @Resource:既可以根据类型注入,也

  • 基于命令行执行带参数的php脚本并取得参数的方法

    本文分析了基于命令行执行带参数的php脚本并取得参数的方法.分享给大家供大家参考,具体如下: 一.为什么我们要在命令行下运行php脚本呢? 个人理解,主要有二个原因: 1. 利用crontab去跑php,可以给服务器减压,当然在这里有一个条件,就是实时性要求不高.比如:sns中的好友动态,这个实时要求不高,但是数据量比较大,这个时候定时跑的话,会给web服务器,数据库服务器分担不小的压力. 2. 就是我们要定时去完成某一事情,比如:我要删除一个月前,用户留言,这个时候,写的php脚本在cront

  • 基于springboot bean的实例化过程和属性注入过程

    目录 bean的实例化过程和属性注入过程 bean实例化流程说明 bean的实例化过程和属性注入过程 了解过springboot的加载流程的都知道springboot初始化bean都在refresh方法中. 这个方法代码如下: // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory.新建beanFactory Config

  • 解析spring加载bean流程的方法

    spring作为目前我们开发的基础框架,每天的开发工作基本和他形影不离,作为管理bean的最经典.优秀的框架,它的复杂程度往往令人望而却步.不过作为朝夕相处的框架,我们必须得明白一个问题就是spring是如何加载bean的,我们常在开发中使用的注解比如@Component.@AutoWired.@Socpe等注解,Spring是如何解析的,明白这些原理将有助于我们更深刻的理解spring.需要说明一点的是spring的源码非常精密.复杂,限于篇幅的关系,本篇博客不会细致的分析源码,会采取抽丝剥茧

  • 基于spring DI的三种注入方式分析

    一.前言: IOC(控制反转)与DI(依赖注入) Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合. 在讲依赖注入之前,我觉得有必要了解一下IOC(控制反转)与DI(依赖注入)的关系,在这篇文章中有详细的介绍:spring IOC 与 DI. 二.DI的三种常见注入方

  • SpringBoot Bean花式注解方法示例下篇

    目录 1.容器初始化完成后注入bean 2.导入源的编程式处理 3.bean裁定 拓展 4.最终裁定 1.容器初始化完成后注入bean import lombok.Data; import org.springframework.stereotype.Component; @Component("miao") @Data public class Cat { } 被注入的JavaBean import org.springframework.context.annotation.Con

随机推荐