简单实现并整合AOP和IOC

最近在看Spring的ioc和aop相关的知识点,看了一点官方的源码,一知半解,只能说对这俩个东西有个宏观的大致的了解,具体实现细节还是不是很清晰。于是参考了网上的aop和ioc简单实现代码,将二者简单整合了起来。当然,这个demo写的还是问题很多,可能得慢慢思考如何进行修改和优化。由于对xml解析的水平不太高,xml解析部分的代码原作者没有封装成函数,可以说是一个遗憾,未来有时间希望可以修改一下。

下面介绍一下大致的实现步骤:

  1. 加载xml文件,遍历其标签
  2. 获取标签中的id和class属性,加载class属性的类,并创建bean
  3. 遍历标签中的属性,获取属性值,并将属性值填充到bean中
  4. 将bean存储到bean容器中
  5. 后处理,找出所有的实现了InvocationHandler接口的类(这些就是advice类)。这个handler对应的切面逻辑类已经在bean的初始化的时候被注入了。从handler的属性中获取需要被代理的bean,创建jdk动态代理,将代理类重新存储到bean容器中。
  6. 通过getBean方法获取代理类,调用其方法进行测试

以下是代码清单:

ioc.xml   //bean的配置文件
SimpleIOC  //IOC和AOP的实现类
Car          //IOC和AOP的测试接口
DazhongCar   //IOC和AOP的测试类
Advice      //继承了InvocationHandler接口的接口
AfterMethodInvocation   //后置通知的逻辑需实现接口(需要使用被代理类的方法返回值)
MethodInvocation   //前置通知的逻辑需实现接口
AfterAdvice   // 代理类,后置通知实现类,实现Advice      
BeforeAdvice  //代理类,前置通知方法实现类,实现Advice 
AfterTask    //后置通知方法实现逻辑
BeforeTask  //前置通知方法实现逻辑
Test         //测试类

以下是详细代码
ioc.xml


 
 
 
    
        
        
    

    
        
        
        
        
        
    
     
     
        
        
        
    

SimpleIOC.java

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class SimpleIOC {
    private Map beanMap = new HashMap();
    public SimpleIOC(String location) throws Exception {
        loadBeans(location);
    }
    public Object getBean(String name) {
        Object bean = beanMap.get(name);
        if (bean == null) {
            throw new IllegalArgumentException("there is no bean with name " + name);
        }

        return bean;
    }
    private void loadBeans(String location) throws Exception {
        // 加载 xml 配置文件
        InputStream inputStream = new FileInputStream(location);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        Document doc = docBuilder.parse(inputStream);
        Element root = doc.getDocumentElement();
        NodeList nodes = root.getChildNodes();
        // 遍历  标签
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                String id = ele.getAttribute("id");
                String className = ele.getAttribute("class");
                // 加载 beanClass
                //反射
                Class beanClass = null;
                try {
                    beanClass = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                    return;
                }
                   // 创建 bean
                Object bean = beanClass.newInstance();

                // 遍历  标签
                NodeList propertyNodes = ele.getElementsByTagName("property");
                if(propertyNodes==null||propertyNodes.getLength()==0) registerBean(id, bean);
                for (int j = 0; j < propertyNodes.getLength(); j++) {
                    Node propertyNode = propertyNodes.item(j);
                    if (propertyNode instanceof Element) {
                        Element propertyElement = (Element) propertyNode;
                        String name = propertyElement.getAttribute("name");
                        String value = propertyElement.getAttribute("value");
                            // 利用反射将 bean 相关字段访问权限设为可访问
                        Field declaredField = bean.getClass().getDeclaredField(name);
                        declaredField.setAccessible(true);

                        if (value != null && value.length() > 0) {
                            // 将属性值填充到相关字段中
                            declaredField.set(bean, value);//set值
                        } else {
                            String ref = propertyElement.getAttribute("ref");//如果是一个自定义的对象,那么需要去找这个对象的值
                            if (ref == null || ref.length() == 0) {
                                throw new IllegalArgumentException("ref config error");
                            }
                            // 将引用填充到相关字段中
                            declaredField.set(bean, getBean(ref));
                        }
                        // 将 bean 注册到 bean 容器中
                        registerBean(id, bean);
                    }
                }
            }
        }
        //bean加载完成
        postProcessAfterInitialization();
        
    }


    private void postProcessAfterInitialization() {
        beanMap.forEach((beanName,bean) -> {
            //是否需要增强
            if(bean instanceof InvocationHandler){
                createProxy(bean);
            }
        });
        
    }

    private void createProxy(Object advice) {
        if(advice instanceof BeforeAdvice){
            String beanName = ((BeforeAdvice) advice).getBeanName();
            Object bean = beanMap.get(beanName);
            if(bean==null){
                new Exception("这个bean "+beanName+"还没被初始化或者这个advice没有绑定bean");
            }
            Object proxy =  Proxy.newProxyInstance(SimpleIOC.class.getClassLoader(), 
                    bean.getClass().getInterfaces(), (BeforeAdvice)advice);
            
            registerBean(beanName, proxy);//重新注册这个bean为它的代理类
        }else if(advice instanceof AfterAdvice){  //后置增强
            String beanName = ((AfterAdvice) advice).getBeanName();
            Object bean = beanMap.get(beanName);
            if(bean==null){
                new Exception("这个bean "+beanName+"还没被初始化或者这个advice没有绑定bean");
            }
            Object proxy =  Proxy.newProxyInstance(SimpleIOC.class.getClassLoader(), 
                    bean.getClass().getInterfaces(), (AfterAdvice)advice);
            registerBean(beanName, proxy);//重新注册这个bean为它的代理类
            
        }
        
        
    }

    private void registerBean(String id, Object bean) {
        beanMap.put(id, bean);
    }

}

Car.java

public interface Car {
    public int driver();

}

DazhongCar.java

public class DazhongCar implements Car {
    private String name;
    private String length;
    private String width;
    private String height;
    private Wheel wheel;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getLength() {
        return length;
    }
    public void setLength(String length) {
        this.length = length;
    }
    public String getWidth() {
        return width;
    }
    public void setWidth(String width) {
        this.width = width;
    }
    public String getHeight() {
        return height;
    }
    public void setHeight(String height) {
        this.height = height;
    }
    public Wheel getWheel() {
        return wheel;
    }
    public void setWheel(Wheel wheel) {
        this.wheel = wheel;
    }
    /* (non-Javadoc)
     * @see spring.aopAndIoc.Car#driver()
     */
    @Override
    public int driver() {
        System.out.println("driver Dazhong car");
        return 1;//运行返回值,测试后置增强
    }
}

Advice.java

public interface Advice extends InvocationHandler{

}

AfterMethodInvocation.java

public interface AfterMethodInvocation {
    void invoke(Object o);

}

AfterAdvice.java

import java.lang.reflect.Method;
public class AfterAdvice implements Advice{
    private Object bean;
    private AfterMethodInvocation afterInvocation;
    private String beanName;

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public AfterMethodInvocation getAfterInvocation() {
        return afterInvocation;
    }
    public void setAfterInvocation(AfterMethodInvocation afterInvocation) {
        this.afterInvocation = afterInvocation;
    }
    public String getBeanName() {
        return beanName;
    }
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
    /* (non-Javadoc)
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = method.invoke(bean, args);
        // 在目标方法执行后调用通知,并使用目标方法的返回值
        afterInvocation.invoke(ret);
        return ret;
    }
}

BeforeAdvice.java

import java.lang.reflect.Method;
public class BeforeAdvice implements Advice{

        private Object bean;
        private String beanName;
        public String getBeanName() {
            return beanName;
        }
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
        private MethodInvocation methodInvocation;
        
        public Object getBean() {
            return bean;
        }
        public void setBean(Object bean) {
            this.bean = bean;
        }
        public MethodInvocation getMethodInvocation() {
            return methodInvocation;
        }
        public void setMethodInvocation(MethodInvocation methodInvocation) {
            this.methodInvocation = methodInvocation;
        }
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 在目标方法执行前调用通知
            methodInvocation.invoke();
            return method.invoke(bean, args);//代理对象调用真实目标对象的方法去处理用户请求
        }
}

AfterTask.java

public class AfterTask implements AfterMethodInvocation{
    //private Object bean

    @Override
    public void invoke(Object o) {
        System.out.println("bean 方法执行的结果是"+o);
    }
}

BeforeTask.java

public class BeforeTask implements MethodInvocation{

    /* (non-Javadoc)
     * @see spring.aopAndIoc.MethodInvocation#invoke()
     */
    @Override
    public void invoke() {
        System.out.println("before the method");
        
    }
}

Test.java

public class Test {
      public static void main(String[] args) throws Exception {
            String location = SimpleIOC.class.getClassLoader().getResource("ioc.xml").getFile();
            SimpleIOC bf = new SimpleIOC(location);
            Wheel wheel = (Wheel) bf.getBean("wheel");
           // DazhongCar car = (DazhongCar) bf.getBean("car");
            //原因:不能用接口的实现类(DazhongCar)来转换Proxy的实现类,它们是同级,应该用共同的接口来转换。
            Car car = (Car) bf.getBean("daZhongCar");
            car.driver();
        }
}

现阶段存在的主要问题:

  • 依赖类必须在配置文件中先被声明,保证先被初始化。需要修改读取配置文件的部分,先读取封装好再来统一初始化。
  • 不解决循环依赖,这个可能还得啃一啃官方源码才能实现吧。

参考:自己动手实现的 Spring IOC 和 AOP - 上篇

你可能感兴趣的:(简单实现并整合AOP和IOC)