Loading

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上面必须也是这个名字,不然还是会报错。

posted @ 2020-06-03 21:57  你见过魔法嘛  阅读(504)  评论(0编辑  收藏  举报