首先,回忆一下JavaBean的三种配置方式:
(1)、基于XML的配置方式;(2)、基于注解的配置方式;(3)、基于Java类的配置方式。
之前可能使用最多的可能就是基于注解的配置方式了,基于XML的配置方式太多臃肿,而Java类的配置方式其实在一定程度上取代了xml的配置方式,特别实在SpringBoot中已经完全采用了Java类的配置方式。Java类的配置方式就是声明一个Java类来配置bean。
下面,开始一个基于Java类配置bean:
1、创建一个实体类:
package spring.createBean.javaClass;
import java.io.Serializable;
/**
* 用户实体类
*/
public class User implements Serializable {
private static final long serialVersionUID = 5239414273866570046L;
private String userName;
private String password;
private Long updateTime;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Long updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "User [userName=" + userName + ", password=" + password + ", updateTime=" + updateTime + "]";
}
}
2、创建DAO层:
package spring.createBean.javaClass;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 数据层
*/
public class UserDao {
public List<User> queryUserList() {
List<User> list = new ArrayList<User>();
//模拟数据库
for (int i = 1; i < 6; i++) {
User user = new User();
user.setUserName("userName" + i);
user.setPassword("password" + i);
user.setUpdateTime(new Date().getTime());
list.add(user);
}
return list;
}
}
3、声明一个Java类,专用于配置bean:
package spring.createBean.javaClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages="spring.createBean.javaClass")
//或者@ComponentScan(basePackageClasses = UserDao.class)
public class SpringBeansConfig {
/**
* 配置Bean时,在该方法上使用@Bean注解
* @return
*/
@Bean
public UserDao getUserDao() {
return new UserDao();
}
}
解释下@Configuration,@ComponentScan(basePackages="包路径"),@Bean:
@Configuration:这个注解其实就是把我们当前的这个类,声明为一个配置文件,它就相当于我们的xml配置文件,跟它的作用是一样的,只不过用类的方式来进行展现;
@ComponentScan(basePackages="包路径"):这个注解其实就是去扫描我们的包路径,对我们需要扫描的包进行扫描,如果需要扫描多个包,之间用逗号隔开即可;除此之外,还可以指定某一个具体的类,例如:@ComponentScan(basePackageClasses = UserDao.class);
@Bean:这个注解其实更好理解,它就相当于xml中的<bean>,我们之前通过<bean>标签将它注入到容器中,现在只需要在你所需要注入的资源上面加上@Bean注解,就可以注入到Spring容器中。
4、创建一个业务层:
package spring.createBean.javaClass;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import spring.careteBean.IUserService;
/**
* 业务层
*/
@Service("userService")
public class UserService implements IUserService{
@Autowired(required = false)
private UserDao userDao;
@Override
public List<User> queryUserList() {
if (null != userDao) {
return userDao.queryUserList();
}
return null;
}
}
解释: @Autowired(required=false)注入注意的问题
(1)@Autowired(required=true):当使用@Autowired直接的时候,其实就是默认使用@Autowired(required=true),此时,该bean必须存在,否则就会注入失败。 当找不到一个匹配的 Bean 时,Spring 容器将抛出 BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。
(2)@Autowired(required=false):表示忽略当前要注入的bean,即在注入的过程中,扫描到公共方法中要注入的bean,并未找到,强行注入@Autowired就会注入失败。我们又不能单独的去除改方法,所以我们采取的思想就是有bean就注入,没有就不注入。解决办法就是@Autowired(required=false)。
最后,写一个测试类:
package spring.createBean.javaClass;
import java.util.List;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestJavaClassBean {
public static void main(String[] args) {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringBeansConfig.class);
UserService userService = context.getBean(UserService.class);
List<User> userList = userService.queryUserList();
if (null != userList) {
for (User user : userList) {
System.out.println(user);
}
} else {
System.out.println("userList is null...");
}
context.destroy();
}
}
测试结果:
——————————————————@Autowired与@Qualifier————————————————
@Autowired默认是按照byType进行注入的,但是当byType方式找到了多个符合的bean,又是怎么处理的?如果发现找到多个bean,则又按照byName方式比对(默认是该类的类名,且首字母是小写),如果还有多个,则报出异常。
解决方案:当创建了多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
也就是说,当发现有多个相同类型的bean时,仅仅使用@Autowired注释是不行的, 因为@Autowired默认是按照byType进行注入的。此时,要结合@Qualifier注释,按照byName方式进行对比。
package spring.createBean.javaClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages="spring.createBean.javaClass")
//或者@ComponentScan(basePackageClasses = UserDao.class)
public class SpringBeansConfig {
/**
* 配置Bean时,在该方法上使用@Bean注解
* @return
*/
@Bean(name = "userDao")
public UserDao getUserDao() {
return new UserDao();
}
@Bean(name = "userDaoTemp")
public UserDao getUserDaoTemp() {
return new UserDao();
}
}
package spring.createBean.javaClass;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import spring.careteBean.IUserService;
/**
* 业务层
*/
@Service("userService")
public class UserService implements IUserService{
@Autowired(required = false)
@Qualifier("userDaoTemp")//不要这个注释,其实也可以成功注入的,因为在配置bean时,第一个Bean的名字是“userDao”,而byName的默认name就是首字母小写的类名。
private UserDao userDao;
@Override
public List<User> queryUserList() {
if (null != userDao) {
return userDao.queryUserList();
}
return null;
}
}
不仅是采用Java类配置bean,采用xml文件配置bean时,出现了此类情况也是一样的:使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
参考:
https://mp.weixin.qq.com/s/1-OkoFpxSbHkLL_37XP1Eg
https://blog.csdn.net/vvhesj/article/details/47661001
https://blog.csdn.net/static_coder/article/details/79580981
http://darkmasky.iteye.com/blog/1129828
Spring学习(二十二) Bean配置的三种方式(XML、注解、Java类)介绍与对比: https://blog.csdn.net/icarus_wang/article/details/51649635