传智播客Spring2.5之施用@Resource注解完成属性装配

传智播客Spring2.5之使用@Resource注解完成属性装配

传智播客Spring2.5之使用@Resource注解完成属性装配

 (2009-08-11 09:41:16)
传智播客Spring2.5之施用@Resource注解完成属性装配转载
标签: 

it

分类: 传智视频学习体会

前面我们都是用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一样使用了!!