Spring框架中@Autowired和@Resource的区别
Spring框架中@Autowired和@Resource的区别
在下载spring源码的漫长过程中....整理一下@Autowired 和 @Resource两个注解的区别和理解
1、注入原理
注入就是为某个对象的外部资源赋值(利用反射机制为类的属性赋值的操作),注入某个对象所需要的外部资源(包括对象、资源、常量数据等)
-
@Autowired是Spring的注解,Autowired默认先按 byType,如果发现找到多个 bean,则,又按照 byName方式比对,如果还有多个,则报出异常;
-
@Resource 是JDK1.6支持的注解,默认按照名称( ByName)进行装配, 如果没有指定 name属性,当注解写在字段上时,默认取字段名,按照名称查找,如果注解写在 setter方法上默认取属性名进行装配。当找不到与名称匹配的 bean时才按照类型进行装配。
但是需要注意的是,如果 name属性一旦指定,就只会按照名称进行装配。
2、简单实例
UserService 接口
@Service
public interface UserService {
public User findByUsername(String username);
}
UserServiceImpl 实现类
@Service
public class UserServiceImpl implements UserService{
@Override
public User findByUsername(String username) {
return username;
}
}
Controller中具体调用
@Controller
public class UserCenterController {
@Autowired
UserService userService;
userService.findByUsername("pianpianpianpian");
}
3、获取实例的具体过程
在Controller类中获取实例 userService时,若使用的是@Autowired,则程序在spring容器中查找相应的类型(UserService类型)的bean,这里刚好有且只有一个对应的bean(UserServiceImpl),则就把UserServiceImpl 自动装配到Controller类的实例(userService)中去了。值得一提的是这里的userService其实就是**UserServiceImpl **这个实现类。
同理,使用@Resource时候
先在容器中查找名为 userService的bean,在这个实例中是肯定找不到的,因为容器中的bean的名字应该是UserServiceImpl (实例中的@Service没有指定bean的value属性,所以注入的bean的名字就是类名,反之如果指定了就是指定的名字)。前面说到按照名字查找没有找到,然后再通过类型查找userService类型的bean,可以找到唯一的一个userService类型的bean(即实现类**UserServiceImpl **)
ps: 小结,个人理解的是 这里的接口是不会被注入bean的,只是用来接收数据和做规范的
通过查阅资料,发现这两个注解的效率是差不多的,不过@Resource可以应对一个接口对应多个实现类的情况,而@Autowired需要结合注解@Qualifier来使用。所以综合来说@Resource更好一点。
4、拓展
Q1、如果遇到一个接口对应多个实现类的情况:
如: UserServiceImpl 和 UserServiceImplSec两个相同类型的类
@Service
public class UserServiceImpl implements UserService{
@Override
public User findByUsername(String username) {
return username;
}
}
@Service
public class UserServiceImplSec implements UserService{
@Override
public User findByUsername(String username) {
return username;
}
}
可以通过以下两种方法确定具体要实例化的类:
1、使用 @Autowired + @Qualifier 或者 @Resource
@Autowired
@Qualifier("UserServiceImpl")
private UserServiceImpl userServiceImpl;
---------------------------------------------------
@Resource(name = "UserServiceImpl")
private UserServiceImpl userServiceImpl;
2、在实现类上添加 @Primary 注解来指定默认加载类
@Service
@Primary
public class UserServiceImpl implements UserService{
@Override
public User findByUsername(String username) {
return username;
}
}
Q2、Controller中明明可以直接实例化实现类UserServiceImpl的bean,为什么却用了接口UserService?
- 这里确实也可以跳过接口直接实例化实现类UserServiceImpl的bean
如:
@Autowired
UserServiceImpl userServiceImpl;
- 使用接口是因为:
- AOP编程思想,屏蔽了方法内部逻辑;
- (通过使用多态)解耦;
- 接口却可以多实现,方便后面的二次开发或维护
- 当业务逻辑简单,变更较少,项目自用时,省略掉接口直接使用实现类更简单明了;反之则推荐使用接口;
Q3、关于注解和xml配置的区别 以及 @Service的具体作用
放一个大佬的传送: 点击前往
重点做一下@Service的的笔记:
在实体类上没有使用@Service的话,spring对应的xml中需要如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="com.xrq" />
<bean id="zoo" class="com.xrq.bean.Zoo" />
<bean id="tiger" class="com.xrq.domain.Tiger" />
<bean id="monkey" class="com.xrq.domain.Monkey" />
</beans>
因为spring的配置文件里面还有12行~14行三个bean,下一步的简化是把这三个bean也给去掉,使得spring配置文件里面只有一个自动扫描的标签,增强Java代码的内聚性并进一步减少配置文件。
使用@Service 后:
java实体类:
@Service
public class Zoo
{
@Autowired
private Tiger ztiger;
@Autowired
private Monkey zmonkey;
}
@Service
public class Tiger
{
private String tigerName;
}
@Service
public class Monkey
{
private String monkeyName;
}
xml中:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="com.xrq" />
</beans>
最后感谢一下今天学习的原博主:点击前往
在放一篇自己感兴趣的文章:传送
补充
发现可能对于@AutoWire 和@Resource的理解不够立体,下面再做一些说明
@Service
public class UserServiceImpl implements UserService{
@Override
public User findByUsername(String username) {
return username;
}
}
-
@AutoWire //当使用这个注入的时候上面的 UserServiceImpl 只需要这样写 @Service,这样就会自动找到UserService这个类型以及他的子类型。UserServiceImpl 实现了UserService这个接口,所以能够找到它。不过这样有一个缺点,就是当UserService实现类有两个以上的时候,这个时候会找哪一个呢,这就造成了冲突,所以要用@AutoWire注入的时候要确保UserService只有一个实现类。
-
@Resource 默认情况下是按照名称进行匹配,如果没有找到相同名称的Bean,则会按照类型进行匹配,。但这里还是有缺点,首先,根据这个注解的匹配效果可以看出,它进行了两次匹配,也就是说,如果你在UserService这个类上面这样写注解,@Service,它会怎么找呢,首先是找相同名字的,如果没有找到,再找相同类型的,而这里的@Service没有写名字,这个时候就进行了两次搜索,显然,速度就下降了许多。
**也许你还会问,这里的@Service本来就没有名字,肯定是直接进行类型搜索啊。其实不是这样的,UserServiceImpl 上面如果有@Service,默认的名字是这个userServiceImpl,注意看,就是把类名前面的大写变成小写,就是默认的Bean的名字了。 **
@Resource根据名字搜索是这样写@Resource("userService"),如果你写了这个名字叫userService,那么UserServiceImpl上面必须也是这个名字,不然还是会报错。