在项目中遇到这么一个困惑

在controller层自动装配了一个service的接口

1
2
@Resource
ProjectService projectService;

==为什么可以直接使用接口实现类重写的方法?==

1
2
3
public List<PostProject> getProjectList(String projectName, String projectStatus){
    return projectService.getProjectList(projectName,projectStatus);
}

ProjectService.java

1
2
3
public interface ProjectService {
    List<PostProject> getProjectList(String projectName, String projectStatus);
}

ProjectServiceImpl.java

1
2
3
4
5
6
7
8
@Service
public class ProjectServiceImpl implements ProjectService{
    @Override
    public List<PostProject> getProjectList(String projectName, String projectStatus) {
        ...
        return postProjectList;
    }
}

@service

接口实现类上的@service注解等价于

xml配置文件上的<bean id="projectServiceImpl" class="service.ProjectServiceImpl"/>

上述配置等价于

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!--Spring中创建对象,在Spring这些都称为bean
	类型 变量名 = new 类型();
	Holle holle = new Holle();
	
	bean = 对象(holle)
	id = 变量名(holle)
	class = new的对象(new Holle();)
	property 相当于给对象中的属性设值,str="Spring"
-->

<bean id="hello" class="pojo.Hello">
    <property name="str" value="Spring"/>
</bean>

controller层上的

1
2
@Resource
ProjectService projectService;

下面先来了解一下@Autowired@Resource

@Autowired

@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired。

@Autowired采取的策略为按照类型注入。

1
2
3
4
public class UserService {
    @Autowired
    private UserDao userDao; 
}

如上代码所示,这样装配会去spring容器中找到类型为UserDao的类,然后将其注入进来。这样会产生一个问题,当一个类型有多个bean值的时候,会造成无法选择具体注入哪一个的情况,这个时候我们需要配合着@Qualifier使用。

@Qualifier告诉spring具体去装配哪个对象。

1
2
3
4
5
public class UserService {
    @Autowired
    @Qualifier(name="userDao1")    
    private UserDao userDao; 
}

这个时候我们就可以通过类型和名称定位到我们想注入的对象

@Resource

@Resource注解由J2EE提供,需要导入包javax.annotation.Resource。

@Resource默认按照ByName自动注入。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class UserService {
    @Resource  
    private UserDao userDao; 
    @Resource(name="studentDao")  
    private StudentDao studentDao; 
    @Resource(type="TeacherDao")  
    private TeacherDao teacherDao; 
    @Resource(name="manDao",type="ManDao")  
    private ManDao manDao; 
}

①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配(当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配);如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

针对不用写setter方法的理解,看下面

1
2
3
4
5
6
7
8
//在Service层的实现类(UserServiceImpl)增加一个Set()方法
//利用set动态实现值的注入!
//DAO层并不写死固定调用哪一个UserDao的实现类
//而是通过Service层调用方法设置实现类!
private UserDao userDao;
public void setUserDao(UserDao userDao){
    this.userDao = userDao;
}
1
((UserServiceImpl)userService).setUserDao(new UserDaoImpl());

set方法中的参数为接口,传入的参数为接口的实现(类似代理模式)

自己的理解:@Resource标注在ProjectService接口上,取属性名(projectService)进行装配,没有找到(@Service标注的ProjectServiceImpl默认名字是projectServiceImpl),再找相同类型的,找到ProjectServiceImpl(这里是通过多态的向上转型的方式判定ProjectServiceImpl和其接口的类型一样,所以虽然我们定义的属性是接口类型的,但是最终时候会装配到实现类上),实现自动装配

参考文章:

https://blog.csdn.net/weixin_40423597/article/details/80643990

https://www.cnblogs.com/jichi/p/10073404.html