詳解JavaSE實現(xiàn)IoC
JavaSE中的IoC實現(xiàn)方式
Java SE 提供了三種方式,可以實現(xiàn)IoC,分別為:
- Java Beans
- Java ServiceLoader SPI
- JNDI(Java Naming and Directory Interface)
Java Beans
java.beans包下的 Introspector 類提供了一個 getBeanInfo的方法,可以獲取一個類的信息
BeanInfo bi = Introspector.getBeanInfo(User.class,Object.class);
如上,則可以獲取User類對象的BeanInfo, 然后我們通過BeanInfo中的 getPropertyDescriptors 方法,可以獲取到User對象中的所有屬性和方法,
注意:java beans中,對于set(xxx)方法,統(tǒng)一叫:writeMethod(), 對于get() 方法,統(tǒng)一叫:readMethod()
Stream.of(bi.getPropertyDescriptors()).forEach(pd->{ Class<?> propertyType=pd.getPropertyType(); Method writeMethod=pd.getWriteMethod(); });
獲取到方法和屬性名稱后,通過反射即可把對應(yīng)的值設(shè)置到對應(yīng)的屬性中
writeMethod.invoke(name,value);
由于我們注入屬性值的時候,我們注入的東西永遠是一個字符串類型,如果需要注入的屬性是其他類型(非字符串), 比如User類中,有一個屬性是address,這個address是一個對象類型,我們應(yīng)該如何定義一個轉(zhuǎn)換器,將字符串類型的值轉(zhuǎn)換為我們需要的對象類型呢?
我們需要通過設(shè)置一個AddressEditor來實現(xiàn)這個轉(zhuǎn)換,這個AddressEditor有如下兩種實現(xiàn)方式:
實現(xiàn)PropertyEditor接口
繼承PropertyEditorSupport類,重寫setAsText方法
PropertyEditorSupport類提供了一些比較便利的實現(xiàn)方式,所以我們采用繼承PropertyEditorSupport類的方法,來實現(xiàn)類型的轉(zhuǎn)換,
Address類的設(shè)計是:
public class Address { private String name; private Integer num; // 省略 get / set / toString }
我們的定義的規(guī)則如下,
輸入的字符串用|來分割 name 和 num屬性
例如: “貝克街|221” 這個字符串 會將“貝克街”賦給name,221賦給num,所以,我們重寫setAsText方法的邏輯如下:
public class AddressEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { String[] tokens = text.split("\\|"); Address address = new Address(); address.setName(tokens[0]); address.setNum(Integer.valueOf(tokens[1])); setValue(address); } }
同理,我們可以實現(xiàn)一個DateEditor,讓“yyyy-MM-dd”這樣類型的字符串轉(zhuǎn)換成日期格式。
public class DateEditor extends PropertyEditorSupport { static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @Override public void setAsText(String text) throws IllegalArgumentException { LocalDate localDate = LocalDate.parse(text, dtf); ZoneId zone = ZoneId.systemDefault(); Instant instant = localDate.atStartOfDay().atZone(zone).toInstant(); setValue(Date.from(instant)); } }
然后,我們需要使用java beans中的PropertyEditorManager類的registerEditor方法把這兩個Editor注冊進來
registerEditor(Address.class,AddressEditor.class); registerEditor(Date.class,DateEditor.class);
最后,PropertyEditorManager的findEditor方法就可以根據(jù)我們前面得到的屬性類型,找到對應(yīng)的Editor來對值進行轉(zhuǎn)換,轉(zhuǎn)換成我們需要的屬性類型的值
PropertyEditor editor=findEditor(propertyType); if(editor!=null){ // 這一步就是為所有屬性找到其對應(yīng)的解析器 editor.setAsText(parameters.get(pd.getName())); try{ writeMethod.invoke(user,editor.getValue()); }catch(IllegalAccessException|InvocationTargetException e){ e.printStackTrace(); } }else{ System.out.println("no editor for:"+pd.getName()); }
主函數(shù)調(diào)用示例
public static void main(String[]args)throws Exception{ Map<String, String> parameters=new HashMap<String, String>(){ { //這里的key要和Node里面的屬性名一致 put("name","福爾摩斯"); put("address","貝克街|221"); put("birthday","1854-01-06"); } }; User convert=PropertyEditorSample.convert(parameters); System.out.println(convert); }
運行結(jié)果
User{name='福爾摩斯', birthday=Thu Jan 05 23:54:17 CST 1854, address=Address{name='貝克街, 221 號}}
SPI
定義支付接口PayService
public interface PayService { void pay(); }
定義多個實現(xiàn):
public class WeixinpayService implements PayService { @Override public void pay() { System.out.println("微信支付"); } } public class AlipayService implements PayService { @Override public void pay() { System.out.println("支付寶支付"); } }
在resources目錄下建立META-INF文件夾,在META-INF文件夾下建立services目錄,同時建立一個文件,名稱為接口的全路徑名,以這個項目為例, PayService的全路徑名稱為:
org.snippets.ioc.java.spi.PayService
在這個文件內(nèi),把實現(xiàn)類的全路徑名寫進去:
org.snippets.ioc.java.spi.AlipayService org.snippets.ioc.java.spi.WeixinpayService
客戶端調(diào)用:
ServiceLoader<PayService> serviceLoader=ServiceLoader.load(PayService.class); for(PayService ele:serviceLoader){ ele.pay(); }
其中ServiceLoader.load方法可以把所有配置的PayService實現(xiàn)得到
執(zhí)行結(jié)果:
支付寶支付
微信支付
JNDI方式
定義一個Person類
public class Person implements Remote, Serializable { private static final long serialVersionUID = 1L; private String name; private String password; // 省略set / get方法 }
實現(xiàn)JNDI的客戶端,實現(xiàn)初始化Person和查找Person兩個功能
public static void initPerson()throws Exception{ //配置JNDI工廠和JNDI的url和端口。如果沒有配置這些信息,將會出現(xiàn)NoInitialContextException異常 LocateRegistry.createRegistry(3000); System.setProperty(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory"); System.setProperty(Context.PROVIDER_URL,"rmi://localhost:3000"); InitialContext ctx=new InitialContext(); //實例化person對象 Person p=new Person(); p.setName("zc"); p.setPassword("123"); //將person對象綁定到JNDI服務(wù)中,JNDI的名字叫做:person。 ctx.bind("person",p); ctx.close(); } public static void findPerson()throws Exception{ //因為前面已經(jīng)將JNDI工廠和JNDI的url和端口已經(jīng)添加到System對象中,這里就不用在綁定了 InitialContext ctx=new InitialContext(); //通過lookup查找person對象 Person person=(Person)ctx.lookup("person"); //打印出這個對象 System.out.println(person.toString()); ctx.close(); }
以上就是詳解JavaSE實現(xiàn)IoC的詳細內(nèi)容,更多關(guān)于JavaSE實現(xiàn)IoC的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Java設(shè)計模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu)
這篇文章主要介紹了Java設(shè)計模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu),享元模式能夠最大限度地重用現(xiàn)有的同類對象,需要的朋友可以參考下2016-04-04Windows7下的Java運行環(huán)境搭建過程圖解
這篇文章主要介紹了Windows7下的Java運行環(huán)境搭建過程圖解,需要的朋友可以參考下2014-04-04SpringBoot登錄、退出、獲取用戶信息的session處理方案
這篇文章主要介紹了SpringBoot登錄、退出、獲取用戶信息的session處理,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08springMVC在restful風(fēng)格的性能優(yōu)化方案
這篇文章主要介紹了springMVC在restful風(fēng)格的性能優(yōu)化方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08