日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring——原理解析-利用反射和注解模拟IoC的自动装配

發(fā)布時(shí)間:2024/4/15 javascript 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring——原理解析-利用反射和注解模拟IoC的自动装配 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

解析Spring的IoC容器基于注解實(shí)現(xiàn)的自動(dòng)裝配(自動(dòng)注入依賴)的原理


1.本文案例
使用注解和反射機(jī)制來模擬Spring中IoC的自動(dòng)裝配功能
定義兩個(gè)注解:@Component,用來標(biāo)注組件;@Autowired,用來標(biāo)記需要被織入的屬性。
定義一個(gè)@Component注解處理器,用來掃描所有組件。
定義一個(gè)bean工廠,用來實(shí)例化組件。
測(cè)試:有兩個(gè)組件,一個(gè)組件被設(shè)置到另一個(gè)組件的屬性中。

2.定義注解
2.1.定義@Component注解
這個(gè)注解表示被標(biāo)注的就是一個(gè)組件,將會(huì)被容器自動(dòng)掃描并創(chuàng)建實(shí)例

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Component {public String id(); }

注解的定義有點(diǎn)類似于接口的定義

注解定義

public @interface Component { }

接口定義

public interface Component { }

區(qū)別只是在于interface這個(gè)標(biāo)識(shí)符前面有沒有@符號(hào)。

并且注解的定義,還需要使用到幾個(gè)原生注解:

@Target(ElementType.TYPE)

這個(gè)注解表明自定義的注解Component是用來標(biāo)記誰的,其中ElementType.TYPE表示這個(gè)注解使用來標(biāo)記類型的,也就是可以標(biāo)記類、接口等。此外還有FIELD、METHOD等,分別表示用來標(biāo)記字段、方法等。

@Retention(RetentionPolicy.RUNTIME)

表示這個(gè)自定義的注解需要保留到什么時(shí)候,如只保留到源碼中,編譯之后就沒有了;或者保留到運(yùn)行時(shí),就是在運(yùn)行的時(shí)候也一直有。這里設(shè)置為運(yùn)行時(shí)。

然后這個(gè)注解中有這樣一行:

public String id();

有點(diǎn)類似于接口中方法的聲明,不過在注解中,這個(gè)表示注解的一個(gè)屬性,后面用到的時(shí)候可以看看是怎么使用的,就明白了。

2.2.定義 @Autowired注解
這個(gè)注解是一個(gè)針對(duì)成員變量的注解,使用這個(gè)注解則表示,這個(gè)字段需要由程序來為其賦值的。

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowire {public String id();}

?

3.定義 Beanfactory(也就是注解處理器)
自定義注解完之后,實(shí)際上并沒有什么用處。要想讓注解發(fā)揮用處,重點(diǎn)在于注解處理器。
首先來明確下這個(gè)處理器干了那些事情,首先根據(jù)給定的組件的包名,掃描這個(gè)包,找出其中所有的被@Component注解標(biāo)注的類,將類型的信息保存下來。
然后提供一個(gè)getBean()方法,允許根據(jù)bean的id來獲取bean。
接下來看看這個(gè)BeanFactory是如何編寫的。

3.1.BeanFactory.java

import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap;public class BeanFactory {private HashMap<String, Object> beanPool;private HashMap<String, String> components;public BeanFactory(String packageName) {beanPool = new HashMap<>();scanComponents(packageName);}private void scanComponents(String packageName) {components = ComponentScanner.getComponentClassName(packageName);}public Object getBean(String id) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {if (beanPool.containsKey(id)) {return beanPool.get(id);}if (components.containsKey(id)) {Object bean = Class.forName(components.get(id)).newInstance();bean = assemblyMember(bean);beanPool.put(id, bean);return getBean(id);}throw new ClassNotFoundException();}private Object assemblyMember(Object obj) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {Class cl = obj.getClass();for (Field f : cl.getDeclaredFields()) {Autowire at = f.getAnnotation(Autowire.class);if (at != null) {Method setMethod = cl.getMethod("set" + captureName(f.getName()), f.getType());setMethod.invoke(obj, getBean(at.id()));}}return obj;}public static String captureName(String name) {char[] cs=name.toCharArray();cs[0]-=32;return String.valueOf(cs);}}

?

?

3.2.ComponentScann.java
這個(gè)BeanFactory在構(gòu)造函數(shù)中使用到了一個(gè)類,用來掃描出一個(gè)包中所有的類的信息。

import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List;public class ComponentScanner {public static HashMap<String, String> getComponentClassName(String packageName) {List<String> classes = getClassName(packageName);HashMap<String, String> components = new HashMap<String, String>();try {for (String cl : classes) {cl = cl.replace("workspace_java.LearningJava.bin.", "");Component comp = Class.forName(cl).getAnnotation(Component.class);if (comp != null) {components.put(comp.id(), cl);}}} catch (ClassNotFoundException e) {// TODO Auto-generated catch block e.printStackTrace();}return components;}public static List<String> getClassName(String packageName) {String filePath = ClassLoader.getSystemResource("").getPath() + packageName.replace(".", "\\"); List<String> fileNames = getClassName(filePath, null);return fileNames;}private static List<String> getClassName(String filePath, List<String> className) { List<String> myClassName = new ArrayList<String>(); File file = new File(filePath); File[] childFiles = file.listFiles(); for (File childFile : childFiles) { if (childFile.isDirectory()) { myClassName.addAll(getClassName(childFile.getPath(), myClassName)); } else { String childFilePath = childFile.getPath(); childFilePath = childFilePath.substring(childFilePath.indexOf("\\classes") + 9, childFilePath.lastIndexOf(".")); childFilePath = childFilePath.replace("\\", "."); myClassName.add(childFilePath); } } return myClassName; }public static void main(String[] args) {getComponentClassName("com.oolong.javase.annotation");}}

?

4.測(cè)試

定義一個(gè)模擬的數(shù)據(jù)庫(kù)訪問接口

@Component(id = "dataAccessInterface") public class DataAccessInterface {public String queryFromTableA() {return "query result";} }

這個(gè)類使用了Component這個(gè)注解,并且注意,這里使用了這個(gè)注解的id屬性。

定義一個(gè)模擬的業(yè)務(wù)接口

@Component(id="businessObject") public class BusinessObject {@Autowire(id="dataAccessInterface")private DataAccessInterface dai;public void print() {System.out.println(dai.queryFromTableA());}public void setDai(DataAccessInterface dai) {this.dai = dai;} }

這個(gè)接口除了使用@Component這個(gè)注解標(biāo)注之外,還有個(gè)成員變量,使用了Autowire這個(gè)注解標(biāo)注。使用這個(gè)注解標(biāo)注,表示這個(gè)成員變量的初始化將會(huì)交給BeanFactory來進(jìn)行。

測(cè)試

public class BeanFactoryTester {public static void main(String[] args) {BeanFactory beanFactory = new BeanFactory("com.oolong.javase.annotation");BusinessObject obj = (BusinessObject) beanFactory.getBean("businessObject");obj.print();}}

這里使用BeanFactory創(chuàng)建了一個(gè)BusinessObject的對(duì)象之后,調(diào)用這個(gè)對(duì)象的print方法,最終打印出來一個(gè)結(jié)果。

而回到這個(gè)類的定義中,可以看到:

public void print() {System.out.println(dai.queryFromTableA()); }

這個(gè)方法調(diào)用的是成員變量dai的queryFromTableA方法。而在這個(gè)類中,只有這個(gè)成員變量的聲明,而沒有賦值。

這個(gè)賦值又是在哪里進(jìn)行的呢?

這個(gè)就是有我們編寫的這個(gè)BeanFactory執(zhí)行的。通過注解和反射機(jī)制,自動(dòng)為類注入依賴。

?

轉(zhuǎn)載于:https://www.cnblogs.com/weilu2/p/spring_ioc_analysis_principle_bsici_on_reflection_annotation.html

總結(jié)

以上是生活随笔為你收集整理的Spring——原理解析-利用反射和注解模拟IoC的自动装配的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。