从Spring2.0以后的版本中,Spring也引入了基于注解(Annotation)方式的配置,开发人员对注解(Annotation)的态度也是萝卜青菜各有所爱,个人认为注解可以大大简化配置,提高开发速度,同时也不能完全取代XML配置方式,XML方式更加灵活,并且发展的相对成熟,这种配置方式为大多数 Spring 开发者熟悉;注解方式使用起来非常简洁,但是尚处于发展阶段,XML配置文件和注解(Annotation)可以相互配合使用。
注解其实也没什么神秘的,和XML配置文件类似都是一种配置的方式而已,只不过利用JDK的反射机制,在编译时或者运行时动态获取所配置的信息而已,注解本身只是个标识,注解的真正意义在于通过注解标识获取注解所在对象的信息以及注解中配置的信息。
Spring的注解方式只是简化了XML配置文件,可以在读入Bean定义资源时可以动态扫描给定的路径,在解析和依赖注入时,XML方式配置的Bean,Spring需要解析XML文件,注解方式配置的Bean,Spring需要通过JDK的反射机制获取注解配置的信息。
虽然 2.0 版本发布以来,Spring 陆续提供了十多个注解,但是提供的这些注解只是为了在某些情况下简化 XML 的配置,并非要取代 XML 配置方式。这一点可以从 Spring IoC 容器的初始化类可以看出:ApplicationContext 接口的最常用的实现类是 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext,以及面向 Portlet 的 XmlPortletApplicationContext 和面向 web 的 X
mlWebApplicationContext,它们都是面向 XML 的。Spring 3.0 新增了另外两个实现类:AnnotationConfigApplicationContext 和 AnnotationConfigWebApplicationContext。从名字便可以看出,它们是为注解而生,直接依赖于注解作为容器配置信息来源的 IoC 容器初始化类。由于 AnnotationConfigWebApplicationContext 是 AnnotationConfigApplicationContext 的 web 版本,其用法与后者相比几乎没有什么差别
使用注解方式时,必须在spring配置文件的schema中添加注解的命名空间如下:
xmlns:context="/schema/context
/schema/context/spring-context-2.5.xsd
是否有了这些 IOC 注释,我们就可以完全摒除原来 XML 配置的方式呢?答案是否定的。有以下几点原因:
1) 注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如 Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对 Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。
2) 如果 Bean 不是自己编写的类(如 JdbcTemplate、S
essionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。
3) 注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于 @Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。
所以在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。
定义配置文件中使用的参数定义文件:
<context:property-placeholder location="classpath:jdbc.properties" />
在后面的配置中就可以使用类似:<property name="url" value="${database.url}" /> 这样的变量来引用属性参数了
=====================================================================
Spring IoC容器对于类级别的注解和类内部的注解分以下两种处理策略:
(1).类级别的注解:如@Component、@Repository、@Controller、@Service以及WebSerivce和JavaEE6的@ManagedBean和@Named注解,都是添加在类上面的类级别注解,Spring容器根据注解的过滤规则扫描读取注解Bean定义类,并将其注册到Spring IoC容器中。
(2).类内部的注解:如@Autowire、@Value、@Required、@Resource以及EJB和WebService相关的注解等,都是添加在类内部的字段或者方法上的类内部注解,SpringIoC容器通过Bean后置注解处理器解析Bean内部的注解。是容器对Bean对象实例化和依赖注入时,通过容器中注册的Bean后置处理器处理这些注解的。
Spring中管理注解Bean定义的容器有两个:AnnotationConfigApplicationContext和 AnnotationConfigWebApplicationContext。这两个类是专门处理Spring注解方式配置的容器,直接依赖于注解作为容器配置信息来源的IoC容器。AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的Web版,它们对于注解Bean的注册和扫描是基本相同的,但是AnnotationConfigWebApplicationContext对注解Bean定义的载入稍有不同。
Spring对注解的处理分为两种方式:
(1).直接将注解Bean注册到容器中:可以在初始化容器时注册;也可以在容器创建之后手动调用注册方法向容器注册,然后通过手动刷新容器,使得容器对注册的注解Bean进行处理。
(2).通过扫描指定的包及其子包下的所有类:在初始化注解容器时指定要自动扫描的路径。
如果容器创建以后向给定路径动态添加了注解Bean,则需要手动调用容器扫描的方法,然后手动刷新容器,使得容器对所注册的Bean进行处理。
======================================================================
配置启用bean注解处理器
Annotati
onConfigApplicationContext通过调用类路径Bean定义扫描器ClassPathBeanDefinitionScanner扫描给定包及其子包下的所有类
当使用Spring的注解功能时,在Spring配置文件中添加如下前两行配置可以开启Spring的注解处理器:
<beans>
<context:annotation-config />
以及四个 Bean 后处理器。这种方式的缺点是使得没有机会再给 HandlerMapping 注入interceptors,
就无法指定
该配置隐式地向Spring容器注册 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor等四个专门用于处理注解的Bean后置处理器。注解后置处理器是Spring容器专门处理配置了自动依赖注入装配相关注解的Bean
也可以单独显式地来启用某个注解处理器,而且可以给处理器添加:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean class="org.springframework.beans.factory.annotation.CommonAnnotationBeanPostProcessor"/>
<bean class="org.springframework.beans.factory.annotation.PersistenceAnnotationBeanPostProcessor"/>
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor">
<property name="interceptors">
<list>
<ref bean="measurementInterceptor" />
</list>
</property>
<property name="order" value="1"></property>
</bean>
</beans>
也可以使用下面的方式来让系统自动扫描类里面的注解
<context:component-scan base-package="company.dao">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 注解特定的类
<context:include-filter type="regex" expression="com\.baobaotao\.service\..*"/> 通过正则表达式定义过滤的类
<context:exclude-filter type="aspectj" expression="com.baobaotao.util..*"/> 通过 AspectJ 表达式定义过滤的类
</context:component-scan>
如上配置,我们就不再需要在 XML 中显式地使用 <bean/> 对该 Bean 进行配置了。Spring 在容器初始化时将自动扫描 base-package 指定的包及其子包下的所有 class 文件,所有标注了 @Repository、@Service、@Controller 和 @Component 的类都将被注册为 Spring Bean。
如果使用了SpringMVC,则下面的语句隐式的向Spring容器注册 DefaultAnnotationHandlerMapping 与 AnnotationMethodHandlerAdapter,用来处理 @RequestMapping, @InitBinder, @NumberFormat, @DateTimeFormat, @RequestBody, @ResponseBody 等注解
<mvc:annotation-driven />
当然了也可以使用如下的方式显式地加载:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.hod.annotation.RequestMappingHandlerAdapter"/>
</beans>
当一个 Bean 被自动检测
到时,会根据那个扫描器的 BeanNameGenerator 策略生成它的 bean 名称。默认情况下,对于包含 name 属性的 @Component、@Repository、 @Service 和 @Controller,会把 name 取值作为 Bean 的名字。如果这个注解不包含 name 值或是其他被自定义过滤器发现的组件,默认 Bean 名称会是小写开头的非限定类名。
四个注解处理器的作用:
(1)AutowiredAnnotationBeanPostProcessor 提供对 Spring 特有的 @Autowired 和 @Qualifier 注释的解析工作
(2)CommonAnnotationBeanPostProcessor 是Spring中用于处理JavaEE5中常用注解(主要是EJB相关的注解)和Java6中关于JAX-WS相关的注解,可以处理@PostConstruct、@PreDestroy等Bean生命周期相关事件的注解,该后置处理最核心的是处理@Resource注解,同时还可以处理JAX-WS相关的
注解
(3)RequiredAnnotationBeanPostProcessor 是Spring中用于处理@Required注解的,@Required注解强制要求Bean属性必须被配置,当Spring容器对Bean的属性进行依赖注入时,配置了@Required注解的属性,Spring容器会检查依赖关系是否设置
(4)PersistenceAnnotationBeanPostProcessor 是Spring中用于处理JPA相关注解的Bean后置处理器,主要解析和处理@PersistenceUnit、@PersistenceContext注解,其主要作用是为JPA的实体管理器工厂(EntityManagerFactory)和实体管理器(EntityManager)注入相应的持久化单元(PersistenceUnit)或持久化上下文(PersistenceContext)。
Spring容器在对WebSerice进行注入时,首先通过JNDI查容器中的实例对象,如果没有到,则根据wsdl文件实例化WebService对象,如果没有指定wsdl文件的路径,则根据类型利用JDK的反射机制生成WebService实例对象,完成注入。
======================================================================
Spring中常用的四个类级别注解:
(1) Component注解原型定义:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component { String value() default ""; } //@Component 有一个可选的入参,用于指定 Bean 的名称
(2) Service注解原型定义:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service { String value() default ""; }
(3) Controller注解原型定义:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller { String value() default ""; }
不用@Controllers注解的处理器则需要实现Controller接口:
public class MyController implements Controller 并且要在xml配置文件中指明controller和urlmapping的映射关系: <bean id="urlMapping" class="SimpleUrlHandlerMapping">
(4) Repository注解原型定义:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository { String value() default ""; }
通过分析Spring这4个常用的注解定义,我们看到:@Service、@Controller和@Repository注解都添加了一个@Component注解,因此他们都属于@Component
使用 @Repository、@Service、@Controller 和 @Component 将类标识为 Bean:
(1) @Repository 注解便属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO 类上即可。示例:
@Repository
public class UserDao {}
为什么 @Repository 只能标注在 DAO 类上呢?这是因为该注解的作用不只是将类识别为 Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。
Spring 本身提供了一个丰富的并且是与具体的数据访问技术无关的数据访问异常结构,用于封装不同的持久层框架抛出的异常,使得异常独立于底层的框架。
(2) @Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
@Repository 通常作用在持久化层,例如setDao()上
@Service 通常作用在业务层,但是目前该功能与 @Component 相同。
@Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。
这三个注解除了作用于不同软件层次的类,其使用方式与 @Component 是完全相同的。
(3) 默认情况下通过 @Component 定义的 Bean 都是 singleton 的,如果需要使用其它作用范围的 Bean,可以通过 @Scope 注释来达到目标
@Scope("prototype") 当从 Spring 容器中获取 boss Bean 时,每次返回的都是新的实例了
@Scope("session") 每个不同的session使用不同的实例
========================================================================
Spring中常用的几个类内部注解:
(1) 使用 @Required 进行 Bean 的依赖检查:
Required 注解只能标注在 Setter 方法之上。因为依赖注入的本质是检查 Setter 方法是否被调用了,而不是真的去检查属性是否赋值了以及赋了什么样的值。如果将该注解标注在非 setXxxx() 类型的方法则被忽略。依赖检查的作用是,判断给定 Bean 的相应 Setter 方法是否都在实例化的时候被调用了。而不是判断字段是否已经存在值了。Spring 进行依赖检查时,只会判断属性是否使用了 Setter 注入。如果某个属性没有使用 Setter 注入,即使是通过构造函数已经为该属性注入了值,Spring 仍然认为它没有执行注入,从而抛出异常。另外,Spring 只管是否通过 Setter 执行了注入,而对注入的值却没有任何要求,即使注入的 <null/>,Spring 也认为是执行了依赖注入。当某个被标注了 @Required 的 Setter 方法没有被调用,则 Spring 在解析的时候会抛出异常
,以提醒开发者对相应属性进行设置
(2) 使用 @Autowired 和 @Qualifier 指定 Bean 的自动装配:
Spring 可以通过bean类的自省自动绑定依赖性,所以不必显式(在xml文件中进行明确配置)指明bean的属性和构造函数。Bean属性可以通过属性名称或类型匹配来实现自动绑定。构造函数通过类型匹配来实现自动绑定。甚至可以指定自动检测 autowiring 模式,根据指定的自动装配规则,将某个 Bean 所需要引用类型的 Bean 注入进来。@Autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。
spring ioc注解
要使@Autowired能够工作,还需要在配置文件中启用如下PostProcessor:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
在XML配置文件中使用的 <bean> 元素中,提供了一个指定自动装配类型的 autowire 属性,该属性有如下选项:
no -- 显式指定(使用 <property name="" value=""/>)不使用自动装配。
byName -- 如果存在一个和当前属性名字一致的 Bean,则使用该 Bean 进行注入。如果名称匹配但是类型不匹配,则抛出异常。如果没有匹配的类型,则什么也不做。
byType -- 如果存在一个和当前属性类型一致的 Bean(相同类型或者子类型),则使用该 Bean 进行注入。byType 能够识别工厂方法,即能够识别 factory-method 的返回类型。
如果存在多个类型一致的 Bean,则抛出异常。如果没有匹配的类型,则什么也不做。
constructor -- 与 byType 类似,只不过它是针对构造函数注入而言的。如果当前没有与构造函数的参数类型匹配的 Bean,则抛出异常。使用该种装配模式时,优先匹配参数最多的构造函数。
autodetect -- 根据 Bean 的自省机制决定采用 byType 还是 constructor 进行自动装配。如果 Bean 提供了默认的构造函数,则采用 byType;否则采用 constructor 进行自动装配。
使用 @Autowired 注解进行装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。
@Autowired 标注作用于数组和使用泛型的集合类型。然后 Spring 会将容器中所有类型符合的 Bean 注入进来。
@Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。
@Autowired 标注作用于普通方法时,会产生一个副作用,就是在容器初始化该 Bean 实例的时候就会调用该方法。当然,前提是执行了自动装配,对于不满足装配条件的情况,该方法也不会被执行。
@Autowired 默认是按
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论