IOC (Inversion of Control) 控制反轉。熟悉Spring的應該都知道。那麼具體是怎麼實現的呢?下面咱們經過一個例子說明。java
package cn.com.qunar.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 指定須要容器管理的類 * * @author WChao * @date 2018-06-23 */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface Component { }
先定義一個@Component註解。只要被@Component自定義主鍵註釋的類都是受容器管理的Bean。緩存
package cn.com.qunar.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 指定須要注入的屬性 * @author WChao * @date 2018-06-23 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Inject { }
定義一個@Inject註解,只要是被@Inject註解註釋的屬性都會自動注入,實現IOC功能。app
package cn.com.qunar.bean; /** * 用戶Bean * * @author WChao * @date 2018-06-23 */ public class User { private String userName; private Integer age; public User(String userName, Integer age) { this.userName = userName; this.age = age; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User [userName=" + userName + ", age=" + age + "]"; } }
只是一個普通的模型bean。ide
package cn.com.qunar.service; import cn.com.qunar.annotation.Component; import cn.com.qunar.bean.User; /** * 用戶Service實現 * * @author WChao * @date 2018-06-23 */ @Component public class UserService { public User getUser() { User user = new User("WChao", 28); return user; } }
UserService實現。使用@Component註解標註該類是受容器管理的類。測試
package cn.com.qunar.controller; import cn.com.qunar.annotation.Component; import cn.com.qunar.annotation.Inject; import cn.com.qunar.bean.User; import cn.com.qunar.service.UserService; /** * 用戶Controller實現 * * @author WChao * @date 2018-06-23 */ @Component public class UserController { @Inject private UserService userService; public void getUser() { User user = userService.getUser(); System.out.println(user); } }
Usercontroller實現,該類被@Component註解註釋,表示受容器管理的Bean。
userService熟悉使用了@Inject自定義註解,表示該屬性是容器自動注入該實例,實現IOC功能。this
package cn.com.qunar.ioc; import java.io.File; import java.io.FileFilter; import java.net.URL; import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import cn.com.qunar.annotation.Component; /** * Ioc 容器實現類 * * @author WChao * @date 2018-06-23 */ public class IocContext { public static final Map<Class<?>, Object> applicationContext = new ConcurrentHashMap<Class<?>, Object>(); static{ String packageName = "cn.com.qunar"; try { initBean(packageName); } catch (Exception e) { e.printStackTrace(); } } private static void initBean(String packageName) throws Exception { Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\\.", "/")); while (urls.hasMoreElements()) { addClassByAnnotation(urls.nextElement().getPath(), packageName); } //IOC實現, 自定注入 IocUtil.inject(); } //獲取指定包路徑下實現 Component主鍵Bean的實例 private static void addClassByAnnotation(String filePath, String packageName) { try { File[] files = getClassFile(filePath); if (files != null) { for (File f : files) { String fileName = f.getName(); if (f.isFile()) { Class<?> clazz = Class.forName(packageName + "." + fileName.substring(0, fileName.lastIndexOf("."))); //判斷該類是否實現了註解 if(clazz.isAnnotationPresent(Component.class)) { applicationContext.put(clazz, clazz.newInstance()); } } else { addClassByAnnotation(f.getPath(), packageName + "." + fileName); } } } } catch (Exception e) { e.printStackTrace(); } } //獲取該路徑下所遇的class文件和目錄 private static File[] getClassFile(String filePath) { return new File(filePath).listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isFile() && file.getName().endsWith(".class") || file.isDirectory(); } }); } }
package cn.com.qunar.ioc; import java.lang.reflect.Field; import java.util.Map; import java.util.Map.Entry; import cn.com.qunar.annotation.Inject; /** * Ioc 注入實現 * * @author WChao * @date 2018-06-23 */ public class IocUtil { public static void inject() { Map<Class<?>, Object> map = IocContext.applicationContext; try { for (Entry<Class<?>, Object> entry : map.entrySet()) { Class<?> clazz = entry.getKey(); Object obj = entry.getValue(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Inject.class)) { Class<?> fieldClazz = field.getType(); field.setAccessible(true); Object fieldObj = map.get(fieldClazz); field.set(obj, fieldObj); } } } } catch (Exception e) { e.printStackTrace(); } } }
循環變量 applicationContext中全部的Bean,判斷每一個Bean中是否有被@Inject註解修飾的屬性,若是有則從applicationContext中獲取要注入的實例,並使用反射實現自動注入功能。url
package cn.com.qunar; import cn.com.qunar.controller.UserController; import cn.com.qunar.ioc.IocContext; /** * 模擬調用UserController * * @author WChao * @date 2018-06-23 */ public class Main { public static void main(String[] args) throws Exception { UserController userController = (UserController)IocContext.applicationContext.get(UserController.class); userController.getUser(); } }
從IocContext 容器中獲取UserController實例,並調用getUser()方法。運行結果結果以下圖。從結果中咱們發現 UserController中的UserService被容器自動注入進來了。而後調用UserService.getUser() 獲取用戶信息。spa