传智播客Spring2.5之使用@Resource注解完成属性装配
前面我们都是用XML配制的方式进行依赖对象的注入的,但是这样都在XML配制就会造成一个BEAN下面可能会有很多的property配置,这样就会使得配置文件变得很臃肿,用Spring2.5的注解方式就能够解决这样的问题,在java代码中使用@Resource注解方式进行装配时,我们首先需要在XML配置文件中配置以下信息:
<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:annotation-config/>
</beans>
?这样我们就开启了spring对注解的支持,这种配置隐式注册了多个注释进行解析处理的处理器:AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor,(注:如果我们想要用这个注解,需要加入Spring安装目录的lib\j2ee\common-annotations.jar文件)。
@Resource这个注解可以标在字段上和属性的setter方法上,但它默认是按名称装配,名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标在字段上,则默认取字段的名称作为bean名寻找依赖对象,当注解标注在属性的setter方法上,既默认取属性名作为bean名称寻找依赖对象
public?class?PersonServiceBean?implements?PersonService {
????@Resource(name=”personDao”)
????private?PersonDao personDao;
}
(注:如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时,@Resource注解会回退到按类型匹配,但一旦指定了name属性,就只能按名称装配了)
到底Spring是如何实现注解装配的呢??咱们还是通过自己编写来实现这样的功能,这样就能很清楚的知道它的底层原理了:
首先我们建立一个自己的Annotation来实现自己的自动装配
//注解信息保留在运行期中,也就是这个注解会出现在源代码、运行期和编译后的档中
@Retention(RetentionPolicy.RUNTIME)
//这个注解只能出现在字段上和方法上
@Target({ElementType.FIELD, ElementType.METHOD})
public?@interface?ItcastResource {
????String name()?default?"";
}
接着我们在构造方法中添加一个处理Annotation的方法,里面的代码如下:
????//这里处理注解注入
????private?void?annotationInject() {
???????for(String beanName : sigletons.keySet()) {
???????????Object bean = sigletons.get(beanName);
???????????if(bean !=?null) {
??????????????try?{
??????????????????//得到bean里面所定义的所有属性描述信息(判断注解在字段setter的情况)
??????????????????PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
??????????????????for(PropertyDescriptor properdesc : ps) {
?????????????????????Method setter = properdesc.getWriteMethod();//获取属性的setter方法
?????????????????????//在属性的setter方法上存在ItcastResource注解
?????????????????????if(setter !=?null?&& setter.isAnnotationPresent(ItcastResource.class)) {
?????????????????????????ItcastResource resource = setter.getAnnotation(ItcastResource.class);
?????????????????????????Object value =?null;
?????????????????????????//注解上指定了name属性
?????????????????????????if(resource.name() !=?null?&& !"".equals(resource.name())) {
????????????????????????????value = sigletons.get(resource.name());
?????????????????????????}?else?{
????????????????????????????//注解上没有指定了name属性
????????????????????????????value = sigletons.get(properdesc.getName());
????????????????????????????if(value ==?null) {
????????????????????????????????//通过属性的名称没有找到指定的对象,接着按该字段的类型进行寻找
????????????????????????????????for(String key : sigletons.keySet()) {
???????????????????????????????????//根椐字段类型到所有的BEAN中查找是否有匹配的类型
???????????????????????????????????if(properdesc.getPropertyType().isAssignableFrom(sigletons.get(key).getClass())) {
???????????????????????????????????????value = sigletons.get(key);
???????????????????????????????????????break;
???????????????????????????????????}
????????????????????????????????}
????????????????????????????}
?????????????????????????}
?????????????????????????setter.setAccessible(true);//允许访问私有的setter方法
?????????????????????????setter.invoke(bean, value);//把引用对象注入到属性中
?????????????????????}
??????????????????}
?
??????????????????//(判断注解在字段的情况)
??????????????????Field[] fields = bean.getClass().getDeclaredFields();//要找私有的字段只能调此方法,如果调用getFileds()就只能找到那些公共的字段
??????????????????for(Field field : fields) {
?????????????????????if(field.isAnnotationPresent(ItcastResource.class)) {
?????????????????????????//字段上存在注解
?????????????????????????ItcastResource resource = field.getAnnotation(ItcastResource.class);
?????????????????????????Object value =?null;
?????????????????????????//注解上指定了name属性
?????????????????????????if(resource.name() !=?null?&& !"".equals(resource.name())) {
????????????????????????????value = sigletons.get(resource.name());
?????????????????????????}?else?{
????????????????????????????//注解上没有指定了name属性
????????????????????????????value = sigletons.get(field.getName());
????????????????????????????if(value ==?null) {
????????????????????????????????//通过属性的名称没有找到指定的对象,接着按该字段的类型进行寻找
????????????????????????????????for(String key : sigletons.keySet()) {
???????????????????????????????????//根椐字段类型到所有的BEAN中查找是否有匹配的类型
???????????????????????????????????if(field.getType().isAssignableFrom(sigletons.get(key).getClass())) {
???????????????????????????????????????value = sigletons.get(key);
???????????????????????????????????????break;
???????????????????????????????????}
????????????????????????????????}
????????????????????????????}
?????????????????????????}
?????????????????????????field.setAccessible(true);//允许访问private字段
?????????????????????????field.set(bean, value);//访问字段的setter方法进行注入
?????????????????????}
??????????????????}
??????????????}?catch?(Exception e) {
??????????????????e.printStackTrace();
??????????????}
???????????}
???????}
????}
这样我们通过自己编写代码来解析这些注解,最后咱们就可用自己建的这个@ItcastResource注解来跟Spring官方实现的@Resource一样使用了!!