首先两者依赖的jar包不同
@Autowired :
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency>org.springframework.beans.factory.annotation.Autowired;
IOC在通过@Autowired进行自动装配时依据的是Type:个人理解是是否实现的接口相同。假设有一个接口TestDao,该接口有一个实现类TestDaoImpl,我们在Service层注入TestDao通过@Autowired注入没有任何问题。
public interface TestDao { void print(); }
import com.tt.dao.TestDao; import org.springframework.stereotype.Repository; @Repository public class TestDaoImpl implements TestDao { @Override public void print() { System.out.println("dao0"); } }
import com.tt.dao.TestDao; import com.tt.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("service") public class TestServiceImpl implements TestService { @Autowired TestDao dao; @Override public void print(){ dao.print(); } }//此时只有一个TestDao的实现类,所以注入成功,没有任何问题
如果我们再实现一个TestDao的实现类TestDaoImpl1,那么再使用@Autowired进行自动和装配时则程序报错
报错信息:
No qualifying bean of type 'com.tt.dao.TestDao' available: expected single matching bean but found 2: testDaoImpl,testDaoImpl1
大致意思是不知道选择哪个Bean去进行自动注入因为发现俩个Type一样的类
从此处也可以看出来,虽然我再@Repositoy并没有进行设置此bean的name,系统的默认命名规则是将该Bean的类名首字母小写来作为此bean的name
这里系统的默认命名规则是可以通过实现Spring提供的一个接口来自定义的
该接口为:BeanNameGenerator可以自定义实现BeanName的生成规则具体操作可参照以下文档
https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/core.html#beans
解决办法:搭配@Qualifier("testDaoImpl")混合使用此时选择的是名为testDaoImpl的Bean进行注入,此时@Qualifier必须有值,也就是在byType的基础上通过byName来获取指定的Bean。
两者必须混合使用才能达到效果:
如果只使用@Qualifier则不能完成注入
Exception in thread "main" java.lang.NullPointerException
at com.tt.service.impl.TestServiceImpl.print(TestServiceImpl.java:15)
at com.tt.Test.main(Test.java:11)
@Resource:
<groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>javax.annotation.Resource;
这里TestDao还是有俩个实现TestDaoImpl和TestDaoImpl1,我通过@Resource注解实现注入会发生什么异常?
import com.tt.dao.TestDao;
import com.tt.service.TestService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service("service")
public class TestServiceImpl implements TestService {
@Resource
TestDao dao;
@Override
public void print(){
dao.print();
}
}
果不其然:@Resource(name = "testDaoImpl")
报错信息:
No qualifying bean of type 'com.tt.dao.TestDao' available: expected single matching bean but found 2: testDaoImpl,testDaoImpl1
这说明@Resource首先默认是根据byType来查找的
此时我将想要的BeanName绑定在该注解的name参数上,程序顺利运行@Resource在没有给name赋值时默认byType注入
验证:
接下来验证一个问题当我给的name是testDaoImpl1,而我已将这个实现类删除,我们如果能注入成功,那么我们可以验证的是@Resource先进行byType注入,如果成功就不再去根据name找对应的BeanName了
如果注入失败,那么该注解在name有值得时候直接是根据byName进行注入的。
结果是:注入失败
结论:当@Resource(name="?")参数name那么有值时通过byName进行注入。
@Resource默认是通过byType进行查找Bean注入的。