spring中提供了向Bean中自动注入依赖的功能,这个过程就是自动装配,当向bean中注入的内容非常多的时候,自动注入依赖的功能将极大的节省注入程序的时间。
Spring自动装配有两类:
基于xml文件的自动装配:byType(类型),byName(名称), constructor(根据构造函数)
基于注解的自动装配:@Autowired,@Resource,@Value
使用xml文件的自动装配有三种类型:
byType byName constructor
在byType(类型模式中)spring容器会基于反射查看bean定义的类,然后找到依赖类型相同的bean注入到另外的bean中,这个过程需要setter注入来完成,因此必须存在setter方法,否则就会注入失败
Dao实现层
public class UserDaoImpl implements UserDao{
@override
public void done(){
System.out.println("UserDaoImpl.invoke.....");
}
}
Service层
public class UserServiceImpl implements UserService{
private UserDao userDao;
@param userDao // 在这里将属性注入了进去
public void setUserDao(UserDao userDao){
this.UserDao=userDao;
}
@override
public void done(){
userDao.done();
}
}
对应的配置文件为:
对应的测试代码为
@Test
public void test3(){
ApplicationContext applicationContext=new ClassPathXMLApplicationContext("/spring/spring-ioc2.xml");
UserSercie userService=(userService)applicationContext.getBean("userService“);
userService.done();
}
总结:通过autowire属性,当属性值为byType的时候,会自动启动实例的注入,装配这个类,在autowire=type模式下,Spring容器将会基于反射查看bean定义的类(查看了之后就知道当前bean有什么依赖了),然后找到与依赖类型相同的bean注入到这个bean中,这个过程就要借助setter注入来完成,因此必须存在set函数
使用autowire=byType注入失败,**因为使用byType是基于类型的注入,因此之关系依赖的类型是什么样,不关心被注入的依赖的名称是否是要求注入的,**因此当xml文件中存在多个相同类型名称,不同的实例Bean的时候,因为存在多种适合的选项,Spring容器不知道应该注入哪种,此时需要我们为spring容器提供帮助指定注入的Bean的实例,在不需要注入的实例Bean中添加标签autowire-candidate=false
使用autowire=byName进行自动装配,此时spring将会尝试将属性名和bean名称进行匹配,如果找到的话就注入依赖中。
autowire=byName进行自动装配的时候,spring容器将会检查需要注意依赖的bean中的依赖名称,当存在依赖的名称时候就将对应得bean注入进去
采用autowire=typeName
**需要注意的是:**如果spring容器中没有找到对应名称可以注入的bean,将不会向依赖中注入任何bean,此时依赖的bean为null。
使用autowire=constructor的时候,spring容器同样会尝试找到那些类型与构造函数相匹配的bean,然后注入
public class UserServiceImpl implements UserService{
private UserDao userDao;
public UserServiceImpl(userDao userDao){
this.userDao=userDao;
}
@override
public void done(){
userDao.done();
}
}
对应的配置文件
autowire=constructor模式下,spring容器会找到类型和构造函数中的类型相匹配的bean,然后注入。
在实际测试开发中当spring容器中出现多个类型和构造函数中的类型相匹配的bean,那么bean的名称和要依赖的名称相同的将会注入进去,会自动将同类不同名的bean过滤掉,如果只有一个bean,类名相同但是名称不同,也会将这个注入到该类中,如果有两个以上bean,类名相同,但是名称不同,这个时候spring容器不知道选择哪一个bean,需要使用autowire-candidate="false"进行过滤。
基于注解的自动装配有三种
@Autowired @Resource @Value
基于xml文件的自动装配虽然是自动装配但是还是需要在xml文件中进行手动注入属性,在bean实例过多的时候,手动设置自动注入属性不太美好。**使用@Autowired注释,可以对成员变量,方法以及构造函数进行标注,完成自动装配的工作。**通过@Autowired的使用标注到成员变量的时候不需要有set方法,Autowired是按照默认类型匹配的
使用注解之前必须要注册注解驱动。
context:annotation-config/
public class UserServiceImpl implements UserService{
// 使用Autowired标注成员变量
@Autowired
private UserDao userDao;
@Autowired 使用autowired标注构造方法
public UserServiceImpl(UserDao userDao){
this.userDao=userDao;
}
@Autowired 使用autowired标注set方法
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
@Override
public void done(){
userDao.done();
}
}
如上所示,通过@Autowired注解通过修饰成员变量,成员方法,构造方法三种方式将userDao依赖注入到UserService中,xml配置文件只要将bean实例声明出来就系那个,在实际开发中建议使用成员变量的注入方式
在使用@Autowired的时候还传递了一个required=fale属性,required属性为false表示userDao实例存在就进行注入不存在的话就忽略,如果required=true,表示必须要进行注入,如果userDao实例不存在就抛出异常。默认情况下@Autowired是按照类型匹配的,如果需要按照名称进行匹配的话,可以使用@Qualifier注解和@Autowired相结合的方式
public class UserServiceImpl implements UserService{
@Autowired
@Qualifier("userDao1") //@Autowired 和@ Qualifier("依赖的名称") 这样就变成了ByName的方式
private UserDao userdao;
}
与@Autowired具备相同效果的是@Resource,@Resource默认使用的是byName的方式进行注入,**使用之前要导入Resource包:Package:javax.annotation.Resource,**可以标注在成员变量和set方法上,但是不能放在构造方法上面,@Resource有两个重要的属性:name type ,spring容器会解析@Resource注解的name属性为bean的名字,type属性为bean的类型,使用@Resource注解的name属性表示按照byName进行解析,使用type属性表示按照byType类型进行解析,不指定的时候默认使用name
@Autowired
@Qualifier("userDao“)
private UserDao userDao;
@Resource(name="userDao") //@Resource注解用于成员变量
private UserDao userDao;
@Resource(name="userDao") //@Resource注解用于成员方法上
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
@Autowired和@Resource进行自动装配注入的依赖都是对象类型,而不是简单的值类型,之前使用配置文件的setter和构造函数的时候可以通过property属性和constructor-arg属性既可以注入对象类型也可以注入简单值类型,对于这些类型,比如 int boolean long String 等等,spring容器提供了@Value注解的注入方式,@Value注解接收一个String的值,该值指定了要注入到 内置的java类型 的属性值(不用担心类型转换),一般情况下@Value属性和properties文件配合使用,分为两种情况,一种是SpEL(类似于js中的EL表达式),一种是占位符方式。如
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&allowMultiQueries=true
jdbc.username=root
jdbc.password=root
public class UserServiceImpl implements UserService {
//标注成员变量
@Autowired
@Qualifier("userDao")
private UserDao userDao;
//占位符方式
@Value("${jdbc.url}")
private String url;
//SpEL表达方式,其中代表xml配置文件中的id值configProperties
@Value("#{configProperties['jdbc.username']}")
private String userName;
@Override
public void done(){
System.out.println("url:"+url);
System.out.println("username:"+userName);
userDao.done();
}
}
对应的xml配置文件为
classpath:/conf/jdbc.properties