new、@Autowired、@Resource的区别
1. new和@Autowired的区别 #
@Autowired注入的对象在注入之前就已经实例化,是从IOC容器中获取已经初始化的对象。
new实例化一个对象,new对象不能注入其他对象,因为new出来的对象声明周期不受IOC容器管控,自然无法完成属性的注入。
换句话说,@Autowired方式是由Spring创建的对象,是单例对象,作用域是整个项目,项目一启动就创建了;而new出来的对象作用域只在此对应的类中,每个调用的时候都是会创建一个新的对象,是多例。
使用@Autowired:
import com.example.SpringBootStudy.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/test")
public class TestController {
@Autowired
private TestService testService;
@RequestMapping(value = "/print",method = RequestMethod.GET)
public void test() {
testService.test();
}
}
import com.example.SpringBootStudy.dao.TestDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestService {
@Autowired
private TestDao testDao;
public void test() {
testDao.test();
}
}
import org.springframework.stereotype.Repository;
@Repository
public class TestDao {
public void test() {
System.out.println("调用成功!");
}
}
调用输出结果:
调用成功!
使用new:
import com.example.SpringBootStudy.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/test")
public class TestController {
//@Autowired
//private TestService testService;
private TestService testService = new TestService();
@RequestMapping(value = "/print", method = RequestMethod.GET)
public void test() {
testService.test();
}
}
输出结果:
报出空指针异常,跟进发现是service中未获取到testDao的值:
总结:
@Autowired是从IOC容器中获取已经初始化的对象,此对象中@Autowired的属性也已经通过容器完成了注入,整个生命周期都交由容器管控。然而通过new出来的对象,生命周期不受容器管控,自然无法完成属性的自动注入。
2. @Autowired和@Resource的区别 #
@Autowired和@Resource都是用来注入对象的。
2.1 @Autowired默认按byType自动装配,而@Resource默认byName自动装配 #
2.1.1 @Autowired的装配顺序:
2.1.2 @Resource的装配顺序:
1.如果同时制定了name和type:
2.如果指定了name:
3.如果指定了type:
4.如果既没有指定name,也没有指定type:
2.2 @Autowired只包含一个参数:required,表示是否开启自动准入,默认是true;而@Resource包含七个参数,其中最重要的两个参数是:name和type #
@Autowired要求依赖对象必须存在,如果不存在会报错。 如果允许null值,可以设置它的required属性为false。
//如果UserDao这个Bean不存在,那么会报错。
@Autowired
private UserDao userDao;
//设置required=false之后,为空也不报错。
@Autowired(required=false)
private UserDao userDao;
2.3 @Autowired如果要使用byName,需要使用@Qualifier一起配合;而@Resource如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配 #
多个实现类可以通过一下两种方式来指定具体使用哪一种实现:
例子代码:
//接口
public interface TestService {
public String test();
}
//实现类1
@Servicepublic class TestServiceImpl implements TestService{
@Override
public String test() {
return "TestServiceImpl";
}
}
//实现类2
@Service
public class TestServiceImpl2 implements TestService{
@Override
public String test() {
return "TestServiceImpl2";
}
}
1、 通过指定bean的名字来明确到底要实例哪一个类
@Autowired 需要结合@Qualifier来使用,如下:
@Autowired
@Qualifier("testServiceImpl")
private TestService testService;
@Resource可直接通过指定name属性的值即可,不过也可以使用@Qualifier(有点多此一举了…)
@Resource(name = "testServiceImpl")
private TestService testService;
@Resource如果不显示的指定name值,就会自动把实例变量的名称作为name的值的,所以也可以直接这样写:
@Resource
private TestService testServiceImpl;
2、 通过在实现类上添加@Primary注解来指定默认加载类
@Service
@Primary
public class TestServiceImpl2 implements TestService{
@Override
public String test() {
return "TestServiceImpl2";
}
}
这样如果在使用@Autowired/@Resource获取实例时如果不指定bean的名字,就会默认获取TestServiceImpl2的bean,如果指定了bean的名字则以指定的为准。
注:
当使用@Resource时,这种写法会报错:
private ProductDao productDao;
private ProductMxDao productZcDao ; // 这2个名称不一样
会提示:productZcDao 不能作为 ProductMxDao 类型注入。
以为@Resource默认按照byName注入,Srping默认将类首字母小写作为bean名字,ProductMxDao的bean名字应该为productMxDao,如果写作productZcDao就找不到了。
如果是@Autowired,则不会报错。
2.4 @Autowired能够用在:构造器、方法、参数、成员变量和注解上;而@Resource能用在:类、成员变量和方法上 #
2.5 @Autowired是Spring定义的注解,而@Resource是JSR-250定义的注解 #
注:
byName 通过参数名 自动装配,如果一个bean的name 和另外一个bean的 property 相同,就自动装配。
byType 通过参数的数据类型自动自动装配,如果一个bean的数据类型和另外一个bean的property属性的数据类型兼容,就自动装配
效率上来说@Autowired/@Resource差不多,不过推荐使用@Resource一点,因为当接口有多个实现时@Resource直接就能通过name属性来指定实现类,而@Autowired还要结合@Qualifier注解来使用,且@Resource是jdk的注释,可与Spring解耦。