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