詳解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);
由于我們注入屬性值的時候,我們注入的東西永遠(yuǎn)是一個字符串類型,如果需要注入的屬性是其他類型(非字符串), 比如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注冊進(jìn)來
registerEditor(Address.class,AddressEditor.class); registerEditor(Date.class,DateEditor.class);
最后,PropertyEditorManager的findEditor方法就可以根據(jù)我們前面得到的屬性類型,找到對應(yīng)的Editor來對值進(jìn)行轉(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)類的全路徑名寫進(jì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的詳細(xì)內(nèi)容,更多關(guān)于JavaSE實現(xiàn)IoC的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring和SpringMVC父子容器關(guān)系初窺(小結(jié))
這篇文章主要介紹了Spring和SpringMVC父子容器關(guān)系初窺(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
如何將默認(rèn)的maven倉庫改為阿里的maven倉庫
這篇文章主要介紹了如何將默認(rèn)的maven倉庫改為阿里的maven倉庫,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12
java算法之Math.random()隨機(jī)概率玩法實例演示
最近打算整理排序算法,發(fā)現(xiàn)很有必要準(zhǔn)備一下生成隨機(jī)數(shù)的工具類,下面這篇文章主要給大家介紹了關(guān)于java算法之Math.random()隨機(jī)概率玩法的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
初識Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運算符
Java是一種強(qiáng)類型語言,每個變量都必須聲明其數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運算符的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10
關(guān)于QueryWrapper,實現(xiàn)MybatisPlus多表關(guān)聯(lián)查詢方式
這篇文章主要介紹了關(guān)于QueryWrapper,實現(xiàn)MybatisPlus多表關(guān)聯(lián)查詢方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教。2022-01-01

