好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

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

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

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

@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类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

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类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

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标签,如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<!-- 定义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。接下来就可以测试效果了:

?

1

2

3

4

5

6

7

8

9

@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标签对应哪一个参数值呢?这就有多种方式指定了。第一种就是直接匹配参数名,配置如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

< 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的构造方法一起阅读,配置方式如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

< 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类型,与第二个构造器匹配,而第一个不匹配:

?

1

2

3

4

5

6

7

8

9

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的配置是这样的:

?

1

2

3

4

5

< 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容器总是使用最后一个满足条件的构造器。

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

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

?

1

2

3

4

5

6

7

8

9

10

11

< 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还是有下面两个构造器:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

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。首先需要一个静态工厂,如下所示:

?

1

2

3

4

5

6

7

8

public class SimpleFactory {

     /**

      * 静态工厂,返回一个Car的实例对象

      */

     public static Car getCar() {

         return new Car( 12345 , 5.4321 );

     }

}

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

<!--

  注意,这里的配置并不是创建一个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:

?

1

2

3

4

5

6

7

8

9

10

11

@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。但是,实例工厂,需要有一个实例对象,才能调用它的工厂方法。先看看实例工厂的定义:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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,而配置文件如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<!-- 声明实例工厂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,看看它们的值,测试代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@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}}

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

原文链接:https://blog.csdn.net/wenwenliuyunabcd/article/details/100291597

查看更多关于基于@Bean修饰的方法参数的注入方式的详细内容...

  阅读:19次