从事过很多家公司,见过很多项目,发现@Autowired和@Resource的使用都是一样的乱,
一个项目中有使用@Autowired的,有使用@Resource的,
甚至有的类中一会儿使用@Autowired,一会儿使用@Resource,虽然不影响业务功能的实现,但看起来真的是杂乱无章。
本篇博客主要讲解这2个注解之间的区别。
@Autowired是Spring框架的注解。
@Resource是Java的注解(来自于JSR-250),由Spring框架兼容支持。
说明:JSR是Java Specification Requests的缩写,意思是Java规范提案。
@Autowired先根据类型查找,如果存在多个Bean,再根据名称查找。
@Resource先根据名称查找,如果查找不到,再根据类型查找。
首先,新建接口:
public interface NotificationService {
    void send();
}
然后新建第一个实现类:
import org.springframework.stereotype.Service;
@Service
public class EmailService implements NotificationService {
    @Override
    public void send() {
        System.out.println("发送邮件通知");
    }
}
接着新建第二个实现类:
import org.springframework.stereotype.Service;
@Service
public class SmsService implements NotificationService {
    @Override
    public void send() {
        System.out.println("发送短信通知");
    }
}
最后新建Controller,并使用@Autowired来注入NotificationService:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController("/dependency/injection/test")
public class NotificationController {
    @Autowired
    private NotificationService notificationService;
}
此时启动项目,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException异常,
原因是因为有2个NotificationService类型的Bean,Spring不确定注入哪一个Bean,这也证明@Autowired默认是先根据类型查找。
有三种解决方案可以解决该问题,
第一种解决方案是使用@Primary注解:
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@Service
@Primary
public class EmailService implements NotificationService {
    @Override
    public void send() {
        System.out.println("发送邮件通知");
    }
}
说明:如果有多个同类型的Bean,Spring会优先使用@Primary注解标记的Bean。
第二种解决方案是修改字段名称:
@Autowired
private NotificationService emailService;
第三种解决方案是使用@Qualifier注解:
@Autowired
@Qualifier("emailService")
private NotificationService notificationService;
第二种解决方案和第三种解决方案证明@Autowired是根据名称查找的,
两者的区别是第二种解决方案是按字段名称查找的(隐式),第三种解决方案是按指定的名称查找的(显式)。
首先,新建接口:
public interface NotificationService {
    void send();
}
然后新建第一个类(注意事项:不是实现类):
import org.springframework.stereotype.Service;
@Service
public class EmailService {
    public void send() {
        System.out.println("发送邮件通知");
    }
}
接着新建第二个类(注意事项:是实现类):
import org.springframework.stereotype.Service;
@Service
public class SmsService implements NotificationService {
    @Override
    public void send() {
        System.out.println("发送短信通知");
    }
}
最后新建Controller,并使用@Resource来注入NotificationService:
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController("/dependency/injection/test")
public class NotificationController {
    @Resource
    private NotificationService emailService;
}
此时启动项目,会抛出org.springframework.beans.factory.BeanNotOfRequiredTypeException异常,
原因是因为按字段名称查找到的EmailService Bean,不是NotificationService类型,这也证明@Resource默认是先根据名称查找。
有两种解决方案可以解决该问题,
第一种解决方案是显式指定Bean名称:
@Resource(name = "smsService")
private NotificationService emailService;
第二种解决方案是修改字段名称:
@Resource
private NotificationService notificationService;
第二种解决方案能注入成功,也证明@Resource是根据类型查找的,
此时因为NotificationService只有一个实现类SmsService,所以直接注入成功,
如果将EmailService也改为NotificationService的实现类:
import org.springframework.stereotype.Service;
@Service
public class EmailService implements NotificationService {
    @Override
    public void send() {
        System.out.println("发送邮件通知");
    }
}
那么启动项目,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException异常。
@Autowired只有1个required参数,@Resource有name、type等7个参数。
@Autowired只有1个参数,如下所示:
public @interface Autowired {
    boolean required() default true;
}
默认情况下,@Autowired要求依赖必须存在,可以通过required = false设置为可选。
@Autowired(required = false)
private NotificationService notificationService;
@Resource有7个参数,如下所示:
public @interface Resource {
    String name() default "";
    String lookup() default "";
    Class> type() default java.lang.Object.class;
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}
默认情况下,@Resource先根据字段名查找Bean,可以通过name参数显式指定名称,通过type参数显式指定类型。
@Resource(name = "emailService", type = NotificationService.class)
private NotificationService notificationService;
@Autowired支持字段注入、Setter方法注入和构造函数注入。
@Resource支持字段注入、Setter方法注入,不支持构造函数注入。
1)字段注入:
@RestController("/dependency/injection/test")
public class NotificationController {
    @Autowired
    private NotificationService notificationService;
}
这种方式不推荐使用,但在实际项目中使用的最多。
2)Setter方法注入:
@RestController("/dependency/injection/test")
public class NotificationController {
    private NotificationService notificationService;
    @Autowired
    private void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}
3)构造函数注入
@RestController("/dependency/injection/test")
public class NotificationController {
    private final NotificationService notificationService;
    public NotificationController(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}
这种方式是Spring官方推荐的首选方式。
1)字段注入:
@RestController("/dependency/injection/test")
public class NotificationController {
	@Resource
    private NotificationService notificationService;
}
2)Setter方法注入:
@RestController("/dependency/injection/test")
public class NotificationController {
    private NotificationService notificationService;
	@Resource
    private void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}
@Resource不支持构造函数注入,如果在构造函数上使用@Resource注解,IDEA会提示:
'@Resource' not applicable to constructor。
@Autowired和@Resource都是用来实现依赖注入的注解,但两者之间是有区别的,主要有以下4点:
来源不同
@Autowired是Spring框架的注解。
@Resource是Java的注解(来自于JSR-250),由Spring框架兼容支持。
依赖查找顺序不同
@Autowired先根据类型查找,如果存在多个Bean,再根据名称查找。
@Resource先根据名称查找,如果查找不到,再根据类型查找。
参数不同
@Autowired只有1个required参数,@Resource有name、type等7个参数。
支持的依赖注入方式不同
@Autowired支持字段注入、Setter方法注入和构造函数注入。
@Resource支持字段注入、Setter方法注入,不支持构造函数注入。
文章持续更新,欢迎关注微信公众号「申城异乡人」第一时间阅读!
 登录查看全部
登录查看全部
                参与评论
手机查看
返回顶部