国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

模擬實現Spring中的注解裝配

2019-11-14 14:50:23
字體:
來源:轉載
供稿:網友

本文原創,地址為http://www.survivalescaperooms.com/fengzheng/p/5037359.html

在SPRing中,xml文件中的bean配置是實現Spring IOC的核心配置文件,在早版本的Spring中,只能基于XML配置文件,配置各個對象之間的依賴關系。在Spring 2.5以后出現了注解,使用注解結合XML的方式,簡化了XML配置的復雜度。

老版本中純XML配置實現IOC

在配置文件中配置如下:

<bean id="userDao" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userService" class="com.springapp.mvc.service.impl.UserServiceImpl">   <property name="userDao" ref="userDao"></property> </bean>

UserServiceImpl的實現如下:

public class UserServiceImpl implements UserService {    public UserDao getUserDao() {        return userDao;    }    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    private UserDao userDao;    public User getUserById(int id){        return userDao.getUserById(id);    }    public int getUserCount(){        return userDao.getUserCount();    }} 

配置的意思是:<property name="userDao" ref="userDao"></property>這行配置是為UserServiceImpl類中的userDao指定userDao這個bean,這樣在UserServiceImpl類中調用userDao的方法,其實就是調用com.springapp.mvc.dao.UserDao的方法。

結合注解的實現方式

配置文件簡化如下:

<bean id="userDao" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userService" class="com.springapp.mvc.service.impl.UserServiceImpl"> </bean>

UserServiceImpl的實現如下:

public class UserServiceImpl implements UserService {    @Autowired    private UserDao userDao;    public User getUserById(int id){        return userDao.getUserById(id);    }    public int getUserCount(){        return userDao.getUserCount();    }}

利用@Autowired注解,實現在xml中<property name="userDao" ref="userDao"></property>的配置,從而實現了自動注入。@Autowired自動注入的規則為byType,意思就是按照被注解字段的類型和xml中配置的bean的類型相匹配,即在UserServiceImpl 類中的userDao為UserDao類型,匹配的時候會在所有bean中查找類型同樣為UserDao的bean。

那么既然是按照類型匹配,如果存在兩個相同類型的bean呢,這時候,就會啟用第二個匹配規則ByName,即根據字段的名字來匹配相同id的bean。如下XML配置:

<bean id="userDao1" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userDao2" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userService" class="com.springapp.mvc.service.impl.UserServiceImpl"></bean>

那么在UserServiceImpl類中應該使用以下這種方式來自動注入:

@Autowiredprivate UserDao userDao1;@Autowiredprivate UserDao userDao2;

這樣好像不是很靈活的樣子,看起來有些不爽,有沒有辦法可以指定要匹配的bean呢?沒錯,是有的。可以使用這樣的方式,通過@Autowired和@Qualifier相結合的方式,@Qualifier后跟的參數就是bean的名稱:

@Autowired@Qualifier("userDao1")private UserDao userDao;

還有更常用的方式,@Resource:

@Resource(name = "userDao1")private UserDao userDao;

關于注解IOC的內容可以參看這篇文章,寫的很詳細。

注解在Spring中的用法講完了,下面來自己實習一個簡單的類,來模擬Spring利用注解實現IOC的原理。

Spring IOC實現原理

1.首先Spring根據bean配置文件,收集所有bean的實例;

2.Spring根據配置文件中的context:component-scan,掃描需要被注入的包(遞歸包中的所有待注入類);

3.掃描待注入類時,判斷是否有特定的注解(例如@Autowired、@Resource),如果有,則進行第4步,注入;

4.注入:根據注解類型或參數,利用反射,為被注解的字段或屬性等設置對應的bean實例。

以上是我個人理解,可能和Spring真正的實現有些出入。

模擬利用注解實現注入

這里要定義一個類似于@Resource的注解,命名為@MyAutowired,定義如下:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.FIELD})@Documentedpublic @interface MyAutowired {	public String name() default "";		public String value() default "";}

定義配置文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:context="http://www.springframework.org/schema/context">	<context:component-scan id="test" class="fengzheng.Test"/>	<bean id="tomoto" class="fengzheng.Tomoto"></bean></beans>

其中bean和Spring中bean的定義是一樣的,而context:component-scan在Spring是定義屬性base-package,之后根據這個屬性,掃描這個包下的所有類,這里為做演示,也定義為一個類,之后會根據這個class屬性,對這個類進行注入。

配置文件中的tomoto bean的定義:

package fengzheng;public class Tomoto {	public void SayHello(){		System.out.println("hello I'm tomoto");	}}

配置文件中fengzheng.Test類定義,這個即為要被注入的類:

package fengzheng;import fengzheng.fzAnnotation.MyAutowired;public class Test {	@MyAutowired(name = "tomoto")	private Tomoto tomoto; 		public void Say(){		tomoto.SayHello();	}}

核心注解分析并實現注入的類:

import java.lang.reflect.Field;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import fengzheng.fzAnnotation.MyAutowired;import java.util.stream.*;public class FzClassPathXMLapplication {	//xml配置文件中 bean定義的集合	private List<BeanDefine> beanList = new ArrayList<BeanDefine>();	// 存儲bean實例和bean的id的對應關系 以便可以根據注解名稱找到對應的實例	Map<String, Object> beanInstanceList = new HashMap<String, Object>();	//xml配置文件中 被掃描類的定義的集合  在Spring框架中 直接掃描一個或多個包	List<ScanDefine> scanList = new ArrayList<ScanDefine>();		// 存儲被掃描的待注入的實體集合	Map<String, Object> annotationInstanceList = new HashMap<String, Object>();		public FzClassPathXMLApplication(String xmlName) {		ReadXml(xmlName);		//實例化所有定義的bean		BeanInstance();				//實例化所有的待注入類		ScanClassInstance();			//開始根據注解實現依賴注入		InjectAnnotation();	}	/**	 * 讀取配置文件  收集bean集合和待注入類的集合	 * @param xmlFileName	 */	public void ReadXml(String xmlFileName) {		URL xmlPath = this.getClass().getClassLoader().getResource(xmlFileName);		System.out.println(xmlPath);		SAXReader reader = new SAXReader();		try {			Document dom = reader.read(xmlPath);			Element root = dom.getRootElement();			List<Element> iters = root.elements();			Stream<Element> beans = iters.stream().filter(bean -> bean.getName().equals("bean"));			Iterator<Element> iterBeans = beans.iterator();			while (iterBeans.hasNext()) {				Element bean = iterBeans.next();				String id = bean.attributeValue("id");				String clsName = bean.attributeValue("class");				//System.out.println("id:" + id + "/nclass:" + clsName);				BeanDefine bd = new BeanDefine();				bd.setId(id);				bd.setClsName(clsName);				beanList.add(bd);			}						Stream<Element> scanClasses = iters.stream().filter(scan -> scan.getName().equals("component-scan"));			//iters.stream().forEach(scan -> System.out.println(scan.getName()));			Iterator<Element> iterScans = scanClasses.iterator();			while (iterScans.hasNext()) {				Element scan = iterScans.next();				String id = scan.attributeValue("id");				String clsName = scan.attributeValue("class");				ScanDefine sd = new ScanDefine();				sd.setId(id);				sd.setClassName(clsName);				scanList.add(sd);			}			System.out.println("scanList.size():"+scanList.size());		} catch (Exception e) {			e.printStackTrace();		}	}	/**	 * 收集bean實例	 */	private void BeanInstance() {		for (BeanDefine bd : beanList) {			try {				Object beanInstance = Class.forName(bd.getClsName()).newInstance();				System.out.println(beanInstance.getClass().getName());				beanInstanceList.put(bd.getId(), beanInstance);			} catch (Exception e) {				e.printStackTrace();			}		}	}	/**	 * 收集被掃描的待注入的類的實例	 */	private void ScanClassInstance(){		for(ScanDefine sd:scanList){			try {				Object scanInstance = Class.forName(sd.getClassName()).newInstance();				System.out.println(scanInstance.getClass().getName());				annotationInstanceList.put(sd.getId(), scanInstance);			} catch (Exception e) {				e.printStackTrace();			}		}	}		/**	 * 循環遍歷待注入的類 	 */	public void InjectAnnotation() {		Iterator<Map.Entry<String, Object>> iters = annotationInstanceList.entrySet().iterator();		while (iters.hasNext()) {			Map.Entry<String, Object> iter = iters.next();			Object scanInstance = iter.getValue();			InjectField(scanInstance);		}			}	/**	 * 注入:把需要注入類中的注解為MyAutowired的字段 注入bean實例	 * @param injectClass	 */	private void InjectField(Object injectClass) {		try {			Field[] fields = injectClass.getClass().getDeclaredFields();						for (Field field : fields) {								if (field != null && field.isAnnotationPresent(MyAutowired.class)) {					System.out.println(field.getName());					MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);					String beanName = myAutowired.name();										Object value = null;					if (beanName != null && !beanName.equals("")) {						value = beanInstanceList.get(beanName);					} else {						Class<?> fType = field.getType();						for (String key : beanInstanceList.keySet()) {							if (fType.isAssignableFrom(beanInstanceList.get(key).getClass())) {								value = beanInstanceList.get(key);								break;							}						}					}					field.setaccessible(true);					field.set(injectClass, value);				}							}		} catch (Exception e) {			e.printStackTrace();		}	}	public Object getScan(String scanName){		return this.annotationInstanceList.get(scanName);	}}

 

注解處理類中用到的兩個實體類:

package fengzheng.simpleSpring;public class BeanDefine {	private String id;		private String clsName;	public String getId() {		return id;	}	public void setId(String id) {		this.id = id;	}	public String getClsName() {		return clsName;	}	public void setClsName(String clsName) {		this.clsName = clsName;	}}package fengzheng.simpleSpring;public class ScanDefine {	public String id;		public String className;	public String getId() {		return id;	}	public void setId(String id) {		this.id = id;	}	public String getClassName() {		return className;	}	public void setClassName(String className) {		this.className = className;	}}

對這段程序邏輯的解釋:

1.首先通過ReadXml()方法讀取配置文件beans.xml,找到其中的bean節點和context:component-scan節點,然后把bean節點實例化為BeanDefine,并加入beanList集合,把component-scan節點實例化為ScanDefine,并加入scanList集合;

2.通過BeanInstance()方法,把配置文件中的bean都實例化存儲到Map集合beanInstanceList中;

3.通過ScanClassInstance()方法,把配置文件中的component-scan節點(即待注入的類)實例化并處處到Map集合annotationInstanceList中;

4.通過InjectAnnotation()方法,遍歷annotationInstanceList集合,為其中的被@MyAutowired注解的字段賦值(即對應的bean的實例)

最后調用實現如下:

FzClassPathXMLApplication ctx = new FzClassPathXMLApplication("beans.xml");Test test =(Test) ctx.getScan("test");test.Say();

輸出結果:


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 德阳市| 通许县| 吉林市| 隆尧县| 驻马店市| 类乌齐县| 咸丰县| 揭西县| 青州市| 原平市| 比如县| 司法| 吴川市| 涿州市| 互助| 藁城市| 南涧| 崇信县| 郸城县| 博湖县| 大英县| 新化县| 南雄市| 万源市| 新密市| 台江县| 沁水县| 彭州市| 于田县| 英山县| 荣昌县| 曲松县| 康平县| 商都县| 三门峡市| 辛集市| 桐梓县| 漳平市| 四会市| 务川| 长子县|