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