zoukankan      html  css  js  c++  java
  • Spring的注解

    Spring常见的注解:@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier

    这几个注解是基于类的,当你需要定义某个类为一个bean时,则在这个类的类名前一行使用类似@Service("XXX")的注解,就相当于把这个类定义为一个bean,bean名称为XXX。当然我们可以定义名称,也可以不定义,不定义名称的话,会默认以类名为bean的名称(类首字母小写)。

    首先,先看一下这几个注解:@Component、@Repository、@Service、@Controller

    通过看一些项目代码,我发现@Repository、@Service、@Controller 这几个注解好像是一个类型,其实@Component 跟他们也是一个类型的。

    Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service和 @Controller ,其实在目前的 Spring 版本中,这三个注解跟@Component 功能是等效的。但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。

    虽然目前这3 个注释和 @Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用上述注解对分层中的类进行注释。

    @Service用于标注业务层组件(通常在service层就用这个,一般是service接口的实现类)

    @Controller用于标注控制层组件(如struts中的action)

    @Repository用于标注数据访问组件(如DAO组件)

    @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

    例如:

    @Service 

    public class UserServiceImpl implements UserService {    

    @Repository 

    public class UserDaoImpl implements IUserDao {  

    }

    因为在一个稍大的项目中,往往会涉及到很多组件,如果组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。Spring2.5以后的版本为我们引入了组件自动扫描机制,它会在配置好的类路径下寻找标注了上述注解的类,并把这些类纳入到spring容器中管理。对组件使用注解的作用和在xml文件中使用bean节点配置组件时是一样的。要使用自动扫描机制,我们需要打开以下配置信息:

    <?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:context="http://www.springframework.org/schema/context" 

        xsi:schemaLocation="http://www.springframework.org/schema/beans 

                    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 

            http://www.springframework.org/schema/context 

            http://www.springframework.org/schema/context/spring-context-2.5.xsd">  

        

        <context:component-scan base-package=”com.foo.spring”/>    

    </beans>

    component-scan标签默认情况下自动扫描指定路径下的包(含所有子包),将带有@Component、@Repository、@Service、@Controller标签的类自动注册到spring容器。对标记了@Required、@Autowired(spring);@PostConstruct、@PreDestroy、@Resource(JSR250);@WebServiceRef(JAX-WS);@EJB(EJB3); @PersistenceContext、@PersistenceUnit(JPA)等注解的类进行对应的操作使注解生效(这其实就包含了annotation-config标签的作用,所以配置了<context:component-scan base-package=""/>之后,便无需再配置<context:annotation-config/>)。

    注意:

    在使用注解的情况下,getBean的默认名称是类名(头字母小写),如果想自定义,可以用类似@Service(“aaaaa”)这样的方式来指定。这种bean默认是“singleton”的,如果想改变,可以使用@Scope(“prototype”)的方式来改变bean的作用域。

    可以使用以下方式指定初始化方法和销毁方法:

     //若想让<bean>实例化之后去执行初始化方法,可以使用@PostConstruct标注在该方法上

    @PostConstruct 

    public void init() {  

    }  

    //同样@PreDestroy注解标注在方法上,可以用来指定<bean>销毁时执行的方法

    @PreDestroy 

    public void destory() {  

    }  

    然后再看后面的几个注解:@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、IocDao2:

    package com.ulewo.ioc;

    import org.springframework.stereotype.Repository;

    @Repository

    public class IocDao implements IIocDao{

        public void add(){

            System.out.println("调用了dao");

        }

    }

    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 这个实现类。奇怪了,它怎么知道我要调用哪个实现呢?

    好,我们修改一下,把 service层中的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");

        }

    }

    这样就把这个实现类的名称定义为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

    我们在service层先这么定义下:

    @Resource(name="iocDao")

    private IIocDao xxx;

    注意:

    @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 xxx; 这个属性名就随便写了。

    运行:调用了dao

    ②如果用@Autowired,

    那么在service层就要这么定义了

    @Autowired

    @Qualifier("iocDao")

    private IIocDao xxx;

    因为Autowired 不能像Resource 那样带个参数指定一个name,就要用Qualifier来指定了。

    @Repository

    public class IocDao implements IIocDao{

        public void add(){

            System.out.println("调用了dao");

        }

    }

    这里也还是用会默认的,也就是这个实现对应的是 iocDao这bean。如果你要为这个类指定别名bean,@Repository("myIocDao"),那么@Qualifier ("myIocDao") 就要这么写了。就是这里的name要跟实现类对应的bean名称保持一致。private IIocDao xxx; 这个属性名就随便写了。

    运行:调用了dao

    而且还可以这么用

    @Resource

    @Qualifier("iocDao")

    private IIocDao xxx;

    等同于

    @Resource(name="iocDao")

    private IIocDao xx;

    记住一点:@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常。而@Resource默认按 byName自动注入罢了。其实spring注解,最常用的还是根据名称,根据类型和构造方法,用的非常少。所以在多个实现的时候我们定义好bean的名称就行,就不会错乱。所以比较推荐使用@Resource!

    总结:其实上面主要说了Spring的主要常见的几个注解的使用场景以及使用方法。通过以上的阐述,基本可以得出一个比较保险的套路:@Repository、@Service、@Controller @Resource这四大注解基本就可以满足Spring 的注解使用范围了。

    补充说明:关于@Autowired的注入方式:

    把DAO实现类注入到action的service接口(注意不要是service的实现类)中,注入时不要new 这个注入的类,因为Spring会自动注入,如果手动再new的话会出现错误,然后属性加上@Autowired后不需要getter()和setter()方法,Spring也会自动注入。 

    在接口前面标上@Autowired注释使得接口可以被容器注入,如:

    @Autowired 

    @Qualifier("chinese") 

    private Man man; 

    当接口存在两个实现类的时候必须使用@Qualifier指定注入哪个实现类,否则可以省略,只写@Autowired。

  • 相关阅读:
    《当大数据遇见网络:大数据与SDN》
    Internet History, Technology and Security (Week 9)
    Internet History, Technology and Security (Week 8)
    Internet History, Technology and Security (Week 7)
    北京讲座所感---6.14~6.15
    Internet History, Technology and Security (Week 6)
    Internet History, Technology and Security (Week 4)
    Internet History, Technology and Security (Week 3)
    Alpha 事后诸葛亮(团队)
    Alpha答辩总结
  • 原文地址:https://www.cnblogs.com/Kevin-mao/p/5743120.html
Copyright © 2011-2022 走看看