一、引入注解的原因:
(1)传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事务,这么做有两个缺点:
- 如果所有的内容都配在.xml文件中,那么.xml文件会十分庞大;如果按需求分开.xml文件,那么.xml文件又非常多。总之将导致配置文件的可读性可维护性变很低。
- 在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。
为了解决这两个问题,Spring引入了注解,
通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。
(2)从JDK1.5之后,Java增强了对注解的支持。其实就是代码里的特殊标记,它用于代替配置文件。也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。
二、常用注解介绍
(一)注解使用的前提
1、声明注解的bean:
使用@Autowired注解,必须先在Spring容器中声明
AutowiredAnnotationBeanPostProcessor
的Bean:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/>
使用 @Required注解,就必须声明
RequiredAnnotationBeanPostProcessor
的Bean:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
使用@Resource、@PostConstruct、@PreDestroy必须声明
CommonAnnotationBeanPostProcessor
;
使用@PersistenceContext注解,必须声明 PersistenceAnnotationBeanPostProcessor的Bean。
以上操作太麻烦,而Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式,即使用
<context:annotation- config/>
隐式地向 Spring容器注册上述三个BeanPostProcessor。
2、配置组件自动扫描路径,开启自动扫描
<context:component-scan/>
其实这个
包
含了自动注入上述BeanPostProcessor的功能
,因此只写<context:annotation-config/>就够了
<
context:component-scan
base-package
="cn.test"/>
可以写多个包,用逗号隔开
<
context:component-scan
base-package
="cn.gacl.dao.impl,cn.gacl.service.impl"/>
(二)注解方式注册Spring容器里的Bean
配置文件就不需要写bean了,可以增强Java代码的内聚性,减少配置文件。
1、写的位置:@XXX,
注解是作用在类上的,放在类的头上,表示让spring去管理这个类。
2、Bean的名字,@XXX("myperson"),或者@XXX(value="myperson"),如果没加括号,没自定义Bean的名字,
默认Bean名字为这个类的类名首字母小写,否则以value作为Bean的名字。
3、Bean的范围,用
@Scope约束,默认是singleton单例,对象全局唯一;定义为@Scope("prototype"),表示将Action的范围声明为原型,每次需要Bean对象,都是生成新的实例
@Scope("prototype")
public
class
UserAction
extends
BaseAction<User>{
……
}
4、四种注解可用来注册Bean:
@Component:(组成、成分)是所有spring管理组件的通用形式,不推荐使用
@Controller:用于标注控制层组件,(Struts里的Action)(servlet)
@Service:用于标注业务逻辑组件,service层
@Repository:(仓库)用于标注数据访问层组件,dao组件
后三个是第一个的引申注解,是为了让标注类本身的用途更清晰,对component做了细分,spring在后续版本中会对其增强,并没有绝对的说哪一层就用哪个。当组件不好归类的时候,就用component
(三)有了Bean之后,如何向Bean中注入别的Bean对象
1、写的位置:可以写在属性上,或者写在setter方法上,还可以在构造方法上——
原理????
2、注解方式注入对象的内部实现:
注解方式不需要setter和getter方法,bean里面不需要写property配置,spring发现对象的属性上或者这个属性的setter方法上有注解的时候
3、三个注解,可实现注入bean对象:
(1)
@Autowired(required=false)
:根据Type类型装配Bean,required可以省略,默认为true。表示这个bean是必须的,如果匹配不上就会抛错,如果required=false,匹配不上直接就是null,不报错
位置:属性、构造函数,或具有任意名称或多个参数的方法(比如setter方法上)。
传统方式,配置文件:通过set方法注入,属性propertry的方式
<bean id="chinese" class="com.cn.DI.ChinesePersonImpl">
<property name="ball"
ref="basket"></property>
</bean>
<bean
id="basket" class="com.cn.DI.BasketIBall"></bean>
注解方式:
Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是
类型匹配,类的名字
)的Bean,并自动注入到相应的地方去。找不到如果还没设置required会抛错。
import
org.springframework.beans.factory.annotation.Autowired;
public
class
Zoo {
@Autowired
private
BasketIBall ball;
public
String play(){
System.out.println(name + "的年龄" + age);
ball.play();
}
}
注意:注入对象的时候,
配置文件优先级比注解要高
,如果配置文件中bean配置了property,会找类中的setter方法,通过setter方法注入,如果没有定义setter方法,则会报错。
注解,如果要注入的是个接口类型的对象,并且对接口的一个实现类添加了注解,那这个接口类型的对象注入的时候就会走那个实例类,也就是说接口也遵循向上原则。
(2)
@Resource,和Autowired差不多,
但它是J2EE提供的,而Autowired是Spring第三方提供的,建议使用resource,以减少代码对spring的依赖
- @Resource后面没有内容,默认通过name去匹配bean,找不到再按type去匹配
- @Resource(name="sss"),指定了name就按name,指定了type就按type,都指定了两个都需要匹配,@Resource(name="foot" type="ball")
(3)
@Qualifier(指定注入Bean的名称),需要和Autowired配合使用,起到过滤的作用
使用场景:如果这个接口有多个实例类,并且多个实例类都配置了bean,这时候spring不知道要引用哪一个bean,会报错,比如Car接口有两个实现类,Spring并不知道应当引用哪个实现类。此时可以使用
@Qualifier注解来指定
Bean的名称
@Autowired
@Qualifier("foot")
private IBall ball;
<bean id="foot" class="com.cn.DI.FootIBall"></bean>
<bean id="basket" class="com.cn.DI.BasketIBall"></bean>
注意:因为需要和Autowired配合使用,而Autowired是根据type找到所有满足的bean,再根据name挑选,如果一个接口有多个实现类的情况,性能不如直接通过name找,推荐使用
@Resource
三、注解总结:
使用注解之前要开启自动扫描功能,其中base-package为需要扫描的包(含子包)。
<
context:component-scan
base-package
="cn.test"/>
@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上),摧毁注解 默认 单例 启动就加载
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 按类型装配
@Autowired @Qualifier("personDaoBean") 按名称装配,存在多个实例配合使用
@Resource 默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@Resource @Qualifier("personDaoBean") 按名称装配,多个实例存在的时候
@Async异步方法调用