现在的位置: 首页 > 综合 > 正文

浅淡spring的注入

2014年09月05日 ⁄ 综合 ⁄ 共 3288字 ⁄ 字号 评论关闭

spring一个很大优点就是通过IOC方式,根据xml配置文件自动注入,从来避免了在java类中直接出现大量的实例化代码,省时省力。

Spring依赖注入方式:

a) 使用构造器注入(使用较少)
b) 使用属性setter方法注入(使用较多,常见方式)
c) 使用Field注入,用于注解方式(使用较多,常见方式)

上述三点有一个共同点都是依靠java反射机制,动态注入。其中c点稍微复杂些,需要在成员变量或者方法前加上注解,注解本身不做任何事情,只是像xml文件一样起到配置作用。注解代表的是某种业务意义,注解背后处理器的工作原理:首先解析所有属性,判断属性上是否存在指定注解,如果存在则根据搜索规则取得bean,然后利用反射原理注入。如果标注在字段上面,也可以通过字段的反射技术取得注解,根据搜索规则取得bean,然后利用反射技术注入。

由于涉及到注解,简单介绍常用的元注解:
@Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括: 
ElemenetType.CONSTRUCTOR 构造器声明 
ElemenetType.FIELD 域声明(包括 enum 实例) 
ElemenetType.LOCAL_VARIABLE 局部变量声明 
ElemenetType.METHOD 方法声明 
ElemenetType.PACKAGE 包声明 
ElemenetType.PARAMETER 参数声明 
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 

@Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括: 
RetentionPolicy.SOURCE 注解将被编译器丢弃 
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃 
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。 

@Documented 将此注解包含在 javadoc 中 

@Inherited 允许子类继承父类中的注解

注解注入有两种方式:@Autowired和@Resource   。@Resource这个注解包的前缀是javax,这是J2EE提供的一个注解,在JDK1.6里就存在了,这个注解不属于Spring的。@Autowired是Spring提供的。这两个注解作用都一样,只是@Resource不属于Spring的,所以没有跟框架紧密耦合。

@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配

    @Resource(name="orderDao")
    private OrderDao orderDao;

@Autowired 默认按类型装配

工作原理:

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context/spring-context-2.5.xsd"

引入上面命名空间以及< context:annotation-config />,该配置注册了多个对注释进行解析处理的处理器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor。

如:AutowiredAnnotationBeanPostProcessor这个处理器专门用来解析@Autowired这个注解的。CommonAnnotationBeanPostProcessor这个处理器专门用来解析@Resource这个注解的;PersistenceAnnotationBeanPostProcessor这个处理器用来处理持久化方面的注解等

下文将通过一个自定义注解来模拟spring的注解注入过程

自主义注解NewResource

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 类ItcastResource.java的实现描述:TODO 类实现描述
 * 
 * @author onlyone 2012-6-19 下午03:42:23
 */

// VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
@Retention(RetentionPolicy.RUNTIME)
// 注解标注在什么地方:字段、方法
@Target( { ElementType.FIELD, ElementType.METHOD })
public @interface NewResource {

    String name() default "";
}

持久层接口OrderDao.java

public interface OrderDao {

    public void insert();
}

服务层接口OrderService.java

public interface OrderService {

    public void save();
}

服务层接口实现OrderServiceImpl.java

public class OrderServiceImpl implements OrderService {

    @NewResource
    private OrderDao orderDao;

    private String   id;

    public OrderServiceImpl(){
    }

    @Override
    public void save() {
        orderDao.insert();
    }
}

根据预定义的注解规则注入对象代码片段

  Field[] fields = bean.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        if (field.isAnnotationPresent(NewResource.class)) {
                            NewResource resource = field.getAnnotation(NewResource.class);
                            Object value = null;
                            //1.按Resource注解的name来注入
                            if (StringUtil.isNotBlank(resource.name())) {
                                value = sigletons.get(resource.name());
                            } else {
                                //2.按成员变量的名称来注入
                                value = sigletons.get(field.getName());
                                if (value == null) {
                                    //3.按成员变量的类型来注入
                                    for (String key : sigletons.keySet()) {
                                        if (field.getType().isAssignableFrom(sigletons.get(key).getClass())) {
                                            value = sigletons.get(key);
                                            break;
                                        }
                                    }
                                }
                            }
                            field.setAccessible(true);// 允许访问private字段
                            field.set(bean, value);
                        }
                    }

测试代码

@Test
    public void instanceBean() {
        MyApplicationContext ctx = new MyApplicationContext("spring/beans.xml");
        OrderService personService = (OrderService) ctx.getBean("orderService");
        personService.save();
    }

代码下载地址:https://webx-schema.googlecode.com/svn/trunk

抱歉!评论已关闭.