容器介面
我們要完成自動裝配,那麼就要有一個存放bean物件的容器,然後要有裝配的註解,那麼哪些類該被存到容器呢,在spring中我們使用過@Service、@Resource等,看下面的程式碼,你也可以做到。
來看看這是一個簡單的容器介面
/**
* 容器介面
* @author:rex
* @create_time:2014-6-26
* @version:V1.0
*/
public interface Container {
Object getBean(String name, BeanType beanType);
Object getBean(Class<?> type, BeanType beanType);
Set<?> getBeanNames();
Collection<?> getBeans();
boolean hasBean(Class<?> clazz);
boolean hasBean(String name);
void registBean(Class<?> clazz);
void initWired();
}
這個容器提供了基礎的存取方法,分別是獲取bean物件和註冊、是否包含bean,還有一個初始化的方法。
接下來我們來為容器做一個基本的實現。
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.biezhi.ioc.BeanType;
import com.biezhi.ioc.Container;
import com.biezhi.ioc.anntation.Autowired;
/**
* 預設的bean容器實現
* @author:rex
* @create_time:2014-6-26
* @version:V1.0
*/
public class DefaultContainerImpl implements Container {
//存放bean的容器
private final Map<String, Object> beansMap = new HashMap<String, Object>();
public DefaultContainerImpl() {
//初始化載入bean
ContainerLoader c = new ContainerLoader(this);
c.init();
}
@Override
public Object getBean(String name, BeanType beanType) {
try {
if(beanType == BeanType.NEW)
return Class.forName(name).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return beansMap.get(name);
}
@Override
public Object getBean(Class<?> type, BeanType beanType) {
try {
if(beanType == BeanType.NEW)
return type.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Iterator<Object> it = this.beansMap.values().iterator();
while(it.hasNext()){
Object obj = it.next();
if(type.isAssignableFrom(obj.getClass())){
return obj;
}
}
return null;
}
@Override
public Set<?> getBeanNames(){
return beansMap.keySet();
}
@Override
public Collection<?> getBeans(){
return beansMap.values();
}
@Override
public boolean hasBean(Class<?> clz) {
if(null != this.getBean(clz, null)){
return true;
}
return false;
}
@Override
public boolean hasBean(String name){
if(null != this.getBean(name, null)){
return true;
}
return false;
}
/**
* 註冊一個bean物件到容器裡
*/
@Override
public void registBean(Class<?> clazz){
String name = clazz.getCanonicalName();
try {
if(!Modifier.isAbstract(clazz.getModifiers()) &&
!Modifier.isInterface(clazz.getModifiers())){
Object obj = clazz.newInstance();
beansMap.put(name, obj);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 初始化注入
*/
@Override
public void initWired(){
Iterator<Object> it = this.beansMap.values().iterator();
try {
while(it.hasNext()){
Object obj = it.next();
Field[] fields = obj.getClass().getDeclaredFields();
for(Field field : fields){
Autowired autowired =
field.getAnnotation(Autowired.class);
if(null != autowired){
//要注入的欄位
Object wiredField =
this.getBean(field.getType(), null);
if(null == wiredField){
throw new RuntimeException("Unable to load "+field.getType().getCanonicalName()+"!");
}
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(obj, wiredField);
field.setAccessible(accessible);
}
}
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
在構造器裡將掃描到的類載入到容器裡,然後提供註冊bean和獲取bean的方法。
import java.io.File;
import java.io.FileFilter;
import java.util.HashSet;
import java.util.Set;
import com.biezhi.ioc.Container;
import com.biezhi.ioc.anntation.Service;
import com.biezhi.ioc.util.ClassHelper;
/**
* 載入容器bean
* @author:rex
* @create_time:2014-6-26
* @version:V1.0
*/
public class ContainerLoader {
private Container container;
public ContainerLoader(Container container) {
this.container = container;
}
public void init(){
//載入要掃描的包,這裡可以使用配置檔案,我們就預設掃描所有類
Set<String> packages = getPackages();
for(String pack : packages){
scanPack(pack);
}
//初始化注入
container.initWired();
}
private void scanPack(String pack){
Set<Class<?>> classes = ClassHelper.scanPackage(pack);
for(Class<?> clazz : classes){
// 這裡我只把帶有@Service註解的存進去了,你也可以存其他的或者全部
Service service = clazz.getAnnotation(Service.class);
if(null != service){
//將掃描到的物件儲存到容器中
container.registBean(clazz);
}
}
}
/**
* 獲取當前classes的包名稱
* @author:rex
* @return
*/
private Set<String> getPackages(){
Set<String> packages = new HashSet<String>();
String appPath = ContainerLoader.class.getResource("/").getPath();
File classDir = new File(appPath);
// 如果存在 就獲取包下的所有檔案 包括目錄
File[] dirfiles = classDir.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isDirectory();
}
});
for(File f : dirfiles){
packages.add(f.getName());
}
return packages;
}
}
這個類是載入需要的類檔案。還有幾個程式碼檔案沒有貼出來,想看程式碼的等會打包自己看。
接下來我們看看這個測試,
@Service
public class A {
String name = "菊花";
public void say(){
System.out.println("hello, I,m rex !");
}
}
@Service
public class B {
@Autowired
private A a;
private String qq = "3838438";
public void hehe(){
a.say();
System.out.println("請問您是" + a.name + "嗎?");
}
public String getQq(){
return this.qq;
}
}
public class Test {
public static void main(String[] args) {
Container c = new DefaultContainerImpl();
c.initWired();
//System.out.println(c.getBeanNames());
B b = (B) c.getBean(B.class, BeanType.SINGLE);
b.hehe();
System.out.println(b.getQq());
System.out.println("==================");
B b2 = (B) c.getBean(B.class, BeanType.NEW);
b2.hehe();
}
}
執行結果:
hello, I,m rex !
請問您是菊花嗎?
3838438
==================
Exception in thread "main" java.lang.NullPointerException
at com.biezhi.ioc.test.B.hehe(B.java:15)
at com.biezhi.ioc.test.Test.main(Test.java:18)
好了,這樣就基本完成了一個簡單的ioc自動裝配。有喜歡的朋友可以參考程式碼。點選下載
快樂賺 http://www.wanzhuanlewangba.com/
www.baiyi1.cn
聚享遊 http://www.tiantanzuan.com/站內文章,如需轉載,請保留作者和出處(雲棲社群),並郵件通知雲棲社群(yqeditor@list.alibaba-inc.com)。
相關文章
- 容器儲存介面--CSI
- C++ 容器介面卡C++
- Java Collection介面 ArrayList集合(容器)Java
- Portainer:Docker容器的Web介面管理工具AIDockerWeb
- 一文讀懂容器儲存介面 CSI
- kubernetes/k8s CNI分析-容器網路介面分析K8S
- kubernetes/k8s CSI分析-容器儲存介面分析K8S
- kubernetes/k8s CRI分析-容器執行時介面分析K8S
- 什麼是K8S的容器執行時CRI介面?K8S
- 從原始碼看Spring中IOC容器的實現(一):介面體系原始碼Spring
- lirantal/dockly:用於管理docker容器和服務的沉浸式終端介面Docker
- 從零開始入門 K8s | 理解容器執行時介面 CRIK8S
- spring4.1.8擴充套件實戰之四:感知spring容器變化(SmartLifecycle介面)Spring套件
- 手寫Spring,定義標記型別Aware介面,實現感知容器物件Spring型別物件
- 以 Kubernetes 為代表的容器技術,已成為雲端計算的新介面
- Vector容器鑲套容器
- Java同步容器和併發容器Java
- 詳解Java 容器(第⑤篇)——容器原始碼分析 - 併發容器Java原始碼
- TP5.1 原始碼窺探之瞭解一下容器實現的三個介面原始碼
- Docker容器Docker
- 集合容器
- lxd容器
- spring容器Spring
- promise容器Promise
- 容器解析
- 容器(collection)
- IoC 容器
- IOC容器
- string容器
- 併發容器與框架——併發容器(二)框架
- 2.1.1. CDB Root容器和系統容器
- 從雲端計算到容器到容器雲
- C++ 向順序容器新增容器C++
- 淺述容器和容器映象的區別
- 容器進階:OCI與容器執行時
- 容器引擎Docker和容器編排kubernetes如何優雅的收集容器日誌Docker
- 容器安全公開課 | 揭秘容器黑產,探討容器安全解決方案
- C++ vector容器的swap方法(容器互換)C++
- 容器生態圈之旅--第二章《容器》