淺淡spring的注入

openkk 12年前發布 | 49K 次閱讀 Spring JEE框架

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


 

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!