Spring 注解关键字解析 @Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier
Java语言欠缺属性、事件、多重继承功能。所以在Java程序中实现一些面向对象编程的常见需求,只能手写大量胶水代码。Java Bean正是编写这套胶水代码的惯用模式或约定。这些约定包括getXxx、setXxx、isXxx、addXxxListener、XxxEvent等,遵守上述约定的类可以用于若干工具或库。
PO (persistence object): 用于持久化时(例如保存到数据库或者缓存);
VO (value object): 用于前端展示使用(例如放置到JSP中解析或者给前端传递数据)
DTO (data transfer object): 用于接口互相调用返回,数据传输(例如很多接口调用返回值或消息队列内容);
使用Spring经常会用到注解,那么这些注解到底有什么区别呢。
@Component、@Repository、@Service、@Controller、@Resource、@Autowired、@Qualifier
Spring2.5提供了基于注解(Annotation-based)的配置,我们可以通过注解的方式来完成注入依赖。
Java代码中可以使用 @Resource或者@Autowired注解方式来经行注入。
虽然@Resource和@Autowired都可以来完成注入依赖,但它们之间是有区别的:
a、@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;
b、@Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;
c、@Resource注解是又J2EE提供,而@Autowired是由Spring提供,故减少系统对Spring的依赖建议使用@Resource的方式(推荐J2EE提供方式@Resource);
d、 @Resource和@Autowired都可以书写标注在字段或者该字段的setter方法之上
分三层来看:Action层、Service层、Dao层
Action 层:
package com.ulewo.ioc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class IocAction { @Autowired private IocService service; public void add(){ service.add(); } }
Service 层:
service就直接定义类了,没有定义接口,定义接口也是一样的
package com.ulewo.ioc; import javax.annotation.Resource; import org.springframework.stereotype.Service; @Service public class IocService { @Resource private IIocDao iocDao; public void add(){ iocDao.add(); } }
Dao 层
先定义一个接口
package com.ulewo.ioc; public interface IIocDao { public void add(); }
然后实现类:@Repository (数据库相关)
package com.ulewo.ioc; import org.springframework.stereotype.Repository; @Repository public class IocDao implements IIocDao{ public void add(){ System.out.println("调用了dao"); } }
然后Spring的配置,这个配置就很简单了,因为是基于注解的,我们不需要再xml中来定义很多
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd"> <context:annotation-config /> <!-- 基于包名的扫描注入 --> <context:component-scan base-package="com.ulewo.ioc" ></context:component-scan> </beans>
如上,让Spring自动扫描包就行了。
然后写测试类:
IocTest:
package com.ulewo.ioc; import junit.framework.TestCase; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class IocTest extends TestCase{ public void testIoc(){ BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml"); IocAction action = factory.getBean("iocAction", IocAction.class); action.add(); } }
运行后,我们会发现 控制台打印:调用了dao
@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier
这几个基本都用到了,除了 @Component @Qualifier
观察会发现@Repository、@Service、@Controller 这几个是一个类型,其实@Component 跟他们也是一个类型的
Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是
@Repository、@Service、@Controller 其实这三个跟@Component 功能是等效的
@Service用于标注业务层组件(我们通常定义的service层就用这个)
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
这几个注解是当你需要定义某个类为一个bean,则在这个类的类名前一行使用@Service("XXX"),就相当于讲这个类定义为一个bean,bean名称为XXX; 这几个是基于类的,我们可以定义名称,也可以不定义,不定义会默认以类名为bean的名称(类首字母小写)。
然后我们在看后面的几个注解
@Resource、@Autowired、@Qualifier
当需要在某个类中定义一个属性,并且该属性是一个已存在的bean,要为该属性赋值我们就用着三个。我们看上面的代码可以看到这三个都是定义在一个属性上的,比如
@Resource private IIocDao iocDao; @Autowired private IocService service;
那这几个到底有什么区别呢?
@Resource,它是javax.annotation.Resource; 这个包中,也就是说是JavaEE中的,并不是Spring中的,而且@Resource("xxx") 是可以定义bean名称的,就是说我这个属性要用那个bean来赋值。
@Autowired,它是org.springframework.beans.factory.annotation.Autowired 是这个包中,它是Spring的包。而且它没有@Autowired("xxx"),那我要为这个bean定义名称怎么办这个时候可以用@Qualifier("xxx") 这个也是Spring中的。这个xxx定义bean名称有什么用呢?我们回头看下刚才的代码。
在IIocDao 这个接口中,我们定义的实现类IocDao 只有一个(IocDao类),好那么我们再定义一个实现类(IocDao2类):
package com.ulewo.ioc; import org.springframework.stereotype.Repository; @Repository public class IocDao2 implements IIocDao{ public void add(){ System.out.println("调用了dao2"); } }
其他不变,我们再运行:testIoc()控制台打印出,调用了dao,所以在service层中
@Resource
private IIocDao iocDao;
这个iocDao 注入的是IocDao 这个实现。
奇了怪了,它怎么知道我要调用哪个实现呢?
修改一下,把
private IIocDao iocDao;
改成
private IIocDao iocDaox
把属性名改一下,再运行,会报错:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: iocDao,iocDao2
错误很明显啊,有两个bean iocDao和iocDao2,但是我们的是iocDaox,所以找不到了。
所以可以看出来在用 @Repository注解来生成bean的时候,如果没有定义名称那么就会根据类名来生成。
所以我们要调用第二个实现的时候可以 定义为 private IIocDao iocDao2
我们再运行:调用了dao2
所以可以根据属性名来区分,到底注入那个bean。
但是有的人说,我不想定义bean名称跟类实现一样,我要定义其他的,那怎么玩呢,方法有2种:
第一种:我们在生成bean的时候就给bean定义个名称
@Repository("myIocDao")
public class IocDao implements IIocDao{
public void add(){
System.out.println("调用了dao");
}
}
当然@Service是一样的,这样就把这个实现定义为myIocDao了,而不是默认的类名 iocDao。
那么我们在使用这个bean的时候就要这么定义了:
@Resource
private IIocDao myIocDao;
运行输出:调用了dao
如果你这里不是用的 myIocDao,你又多加了一个x,成了myIocDaox,你运行会是这样的:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: myIocDao,iocDao2
所以,要自定义bean的名称可以在类注解的时候指定。
第二种:在注入bean的时候指定名称
先看@Resource
我们这么定义下:
@Resource(name="iocDao")
private IIocDao xx;
注意:
@Repository public class IocDao implements IIocDao{ public void add(){ System.out.println("调用了dao"); } }
这里还是用会默认的,也就是这个实现对应的是 iocDao这bean。
如果你要为这个类指定别名bean,@Repository("myIocDao"),那@Resource(name="myIocDao") 就要这么写了。就是这里的name要跟实现类对应的bean名称保持一致。private IIocDao xx; 这个属性名就随便写了。
运行:调用了dao
如果用Autowired就要这么写了
@Autowired
@Qualifier("iocDao")
private IIocDao xx;
因为Autowired 不能像Resource 那样带个参数指定一个name,就要用Qualifier来指定了。
而且还可以这么用
@Resource
@Qualifier("iocDao")
private IIocDao xx;
等同于
@Resource(name="iocDao")
private IIocDao xx;
记住一点:
@Resource的作用相当于@Autowired,
只不过@Autowired按byType自动注入,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常
而@Resource默认按 byName自动注入罢了。
其实spring注解,最常用的还是根据名称;根据类型、构造方法啊,用的非常少。所以在多个实现的时候我们定义好bean的名称就行,就不会错乱。
说了这么多,不知道对着几个注解是不是了解多一点了呢,貌似这些注解 没有根本上的区别,就看你习惯怎么用了。拿代码多跑几次,然后根据自己的想法改改,你就明白这几个注解的用处啦。
参考推荐:
Spring注解@Resource和@Autowired区别对比
request.getParameter() 和request.getAttribute() 区别
Spring 具体分析applicationContext.xml和spring3-servlet.xml
Maven 搭建 SpringMVC+Spring+MyBatis 框架实战
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2017-06-26 03:36:54
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
转载注明: Spring 注解关键字解析 @Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier (米扑博客)