ioc java_从零手写 IOC容器

概述

IOC (Inversion of Control) 控制反转。熟悉Spring的应该都知道。那么具体是怎么实现的呢?下面我们通过一个例子说明。

1. Component注解定义

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。

2. Inject注解定义

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功能。

3. 用户Bean实现

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。

4. UserService实现

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注解标注该类是受容器管理的类。

3. UserController实现

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功能。

6. IocContext 容器实现

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, Object> applicationContext = new ConcurrentHashMap, Object>();

static{

String packageName = "cn.com.qunar";

try {

initBean(packageName);

} catch (Exception e) {

e.printStackTrace();

}

}

private static void initBean(String packageName) throws Exception {

Enumeration 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();

}

});

}

}

扫描加载指定包路径下的所有的Class,并判断该Class是否是@Component注解的类,如果是,则创建实例,并保存到applicationContext缓存中。

调用IocUtil.inject(),进行依赖注入。

7. Ioc 依赖注入实现

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, Object> map = IocContext.applicationContext;

try {

for (Entry, 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中获取要注入的实例,并使用反射实现自动注入功能。

8. 模拟调用UserController测试类

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() 获取用户信息。

运行结果

6c515800ff1b0e3f2d9ddcf9bf5abb38.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值