目录
一、@Bean 的简单使用
1、正常情况
2、问题提出
二、解决方案
1、@Qualifier
2、直接写方法名
三、特殊情况
1、DataSource
在开发中,基于 XML 文件配置 Bean 对象的做法非常繁琐且不好维护,因此绝大部分情况下都是使用“完全注解开发”。
对于 Spring 而言,IOC 容器中的 Bean 对象的创建和使用是一大重点,Spring 也为我们提供了注解方式创建 bean 对象:使用 @Bean。
在举例之前,先熟悉以下两个需要用到的类:
(1)User 类
package com.demo.pojo; import org.springframework.stereotype.Component; @Component public class User { private String name; public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
(2)Book 类
package com.demo.pojo; import org.springframework.stereotype.Component; @Component public class Book { private User user; public void setUser(User user) { this.user = user; } public User getUser() { return user; } }
(1)下面是一个简单的 bean 对象创建:
@Bean public User getUser() { return new User(); }
经此操作,IOC 中就会多出一个与
(2)含有普通类型参数的 bean 对象创建:
@Bean public User getUser(@Value("wyt") String name) { User user = new User(); user.setName(name); return user; }
需要注意的是,方法中的参数并不是 bean 对象的成员属性,而是代表着 bean 对象的创建依赖于这几个参数,或许用来 setParameter,或许只是中间变量。
而在 xml 文件中的
(3)含有对象类型参数的 bean 对象创建:
package com.demo.config; import com.demo.pojo.Book; import com.demo.pojo.User; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; @Configuration public class Config { @Bean public User getUser(@Value("wyt") String name) { User user = new User(); user.setName(name); return user; } @Bean public Book createBook(User user) { Book book = new Book(); book.setUser(user); return book; } }
对比在 xml 中是如何实现参数是对象类型时的属性注入:
(4)正常情况下,@Bean 使用总结
(4-1)@Bean 注解的方法,其返回值就是一个
(4-2)@Bean 对象的实例化依赖于方法内的参数,参数可以是普通类型,也可以是对象类型。
根据上述内容,我们会想到:如果参数是对象类型,可是 IOC 中拥有不止一个相同类型的 bean 对象,这该怎么办呢?
比如下面的情况:
可以看到,Book 对象的参数 user 已经报错了,无法自动装配,因为存在多个 User 类型的 Bean,Spring 不知道应该将哪个 bean 注入到 user 中。
首先我们要知道,默认情况下,参数的注入使用的是 @Autowired,不需要显式写出。
我们可以想到,@Autowired 是根据类型自动装配,当一个类型有多个 bean 对象时失效。
而 @Qualifier 是根据名称进行装配,这不就意味着我们可以用 @Qualifier 来明确需要的 bean 对象嘛。
这有两种写法,都是有效的:
(1)配置类
package com.demo.config; import com.demo.pojo.Book; import com.demo.pojo.User; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; @Configuration public class Config { @Bean public User getUser(@Value("wyt") String name) { User user = new User(); user.setName(name); return user; } @Bean public User createUser(@Value("wyt") String name) { User user = new User(); user.setName(name); return user; } @Bean public Book createBook(@Qualifier("createUser") User user) { Book book = new Book(); book.setUser(user); return book; } }
(2)测试代码
@Test public void SameObjectTest() { ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); Book book = context.getBean("createBook", Book.class); System.out.println(book.getUser()); }
(3)输出结果
因为一般情况下,方法名不能相同,因此也可以通过将参数名写成对应的方法名来进行注入。
package com.demo.config; import com.demo.pojo.Book; import com.demo.pojo.User; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; @Configuration public class Config { @Bean public User getUser(@Value("wyt") String name) { User user = new User(); user.setName(name); return user; } @Bean public User createUser(@Value("wyt") String name) { User user = new User(); user.setName(name); return user; } @Bean public Book createBook(User createUser) { Book book = new Book(); book.setUser(createUser); return book; } }
在这里要说明一些特别的对象类型,比如:DataSource。
(1)问题描述
@Bean public DruidDataSource createDruidDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } @Bean public DruidDataSource getDruidDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; }
当我们像上面的代码一样,写了两个数据源的 bean 对象之后,运行就会出现如下报错:
No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 2
简单来说,就是因为 Spring 有其自身的配置类,导致程序不知道选择哪一个数据源。
(2)解决方法
给其中任意一个加上 @Primary,代表当出现多个同类型 bean 时,优先使用哪一个。写上之后,就可以使用前文所述的方法,如:@Qualifier 或直接写方法名。
@Bean @Primary public DruidDataSource createDruidDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; }