• 实现简单IOC和AOP容器


    AOP思想的实现方法一般是代理模式。jdk只支持接口的代理,而对于类的代理,Spring支持了CGLIB,AspectJ动态代理。

    IOC的实现原理是反射。

    如果我们要做一个简单的IOC容器。

    首先实现简单的四步:

    1.扫描xml配置文件。

    2.遍历所有的bean节点。读取id和class属性

    3.遍历bean节点下每个property节点的name和value或ref值。将值注入到属性中

    4.将加载的bean注入到容器中

    为了实现上述功能,创建如下几个类:

    springIOC     ioc的实现类

    springIOCTest  ioc测试类

    car  汽车实体类

    wheel 车轮实体类

    ioc.xml ioc配置文件

    springIOC类:

    package SpringIOC;
    
    import java.io.FileInputStream;
    import java.lang.reflect.Field;
    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 SpringIOC {
        private Map<String, Object> map = new HashMap<>();
        
        public SpringIOC(String xmlName) throws Exception{
            loadbean(xmlName);
        }
        
        public Object getbean(String beanName){
            Object bean = map.get(beanName);
            if(bean == null){
                throw new IllegalArgumentException();
            }
            return bean;
        }
        private void registerBean(String id, Object bean) {
             map.put(id, bean);
            }
        public void loadbean(String xmlName) throws Exception{
            FileInputStream fileInputStream = new FileInputStream(xmlName);
            DocumentBuilderFactory factory  = DocumentBuilderFactory.newInstance();
            DocumentBuilder newDocumentBuilder = factory.newDocumentBuilder();
            Document Document = newDocumentBuilder.parse(fileInputStream);
            Element root = Document.getDocumentElement();
            NodeList childNodes = root.getChildNodes();
            for(int i =0;i<childNodes.getLength();i++){
                Node node = childNodes.item(i);
                if(node instanceof Element){
                    Element element = (Element)node;
                    String id = element.getAttribute("id");
                    String className = element.getAttribute("class");
                    Class<?> beanClass  = null;
                    try {
                        beanClass = Class.forName(className);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return;
                    }
                    
                    Object bean = beanClass.newInstance();
                    //解析property属性值,并注入
                    NodeList propertyList = element.getElementsByTagName("property");
                    for(int j=0;j<propertyList.getLength();j++){
                        Node propertyItem = propertyList.item(j);
                        if(propertyItem instanceof Element){
                            Element property = (Element)propertyItem;
                            String name = property.getAttribute("name");
                            String value = property.getAttribute("value");
                            //利用反射机制将类的内部属性变为可访问的
                            Field filed = bean.getClass().getDeclaredField(name);
                            filed.setAccessible(true);if(value != null && value.length()>0){
                                filed.set(bean, value);
                            }else{
                                String ref = property.getAttribute("ref");
                                if (ref == null || ref.length() == 0) {
                                    throw new IllegalArgumentException("ref config error");
                                }
                                filed.set(bean, getbean(ref));
                            }
                        }
                    }
                    registerBean(id, bean);
                }
            }
        }
    }

    由此可知IOC的实现原理是反射。

    springIOCtext类:

    package SpringIOC;
    
    public class SpringIOCTest {
        public static void main(String[] args) throws Exception {
            SpringIOC springIOC = new SpringIOC("C:/file/Workspaces/StringTest/bin/SpringIOC/ioc.xml");
            Car car = (Car)springIOC.getbean("car");
            Wheel wheel = (Wheel)springIOC.getbean("wheel");
            System.out.println(car);
            System.out.println(wheel);
        }
    }

    实体类和ioc.xml:

    package SpringIOC;
    
    public class Car {
        private String Carbrand;
        private Wheel wheel;
        public String getCarbrand() {
            return Carbrand;
        }
        public void setCarbrand(String carbrand) {
            Carbrand = carbrand;
        }
        public Wheel getWheel() {
            return wheel;
        }
        public void setWheel(Wheel wheel) {
            this.wheel = wheel;
        }
        
    
        @Override
        public String toString() {
            return "Car [Carbrand=" + Carbrand + ", wheel=" + wheel + "]";
        }
    }
    package SpringIOC;
    
    public class Wheel {
        private String wheelBrand;
        private String width;
        private String height;
        public String getWheelBrand() {
            return wheelBrand;
        }
        public void setWheelBrand(String wheelBrand) {
            this.wheelBrand = wheelBrand;
        }
        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;
        }
    
        @Override
        public String toString() {
            return "Wheel [wheelBrand=" + wheelBrand + ", width=" + width + ", height=" + height + "]";
        }
    }
    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans>
        <bean id="wheel" class="SpringIOC.Wheel">
            <property name="wheelBrand" value="米其林">
            </property>
            <property name="width" value="50">
            </property>
            <property name="height" value="50">
            </property>
        </bean>
        <bean id="car" class="SpringIOC.Car">
            <property name="Carbrand" value="奔驰">
            </property>
            <property name="wheel" ref="wheel">
            </property>
        </bean>
    </beans>

    这里就简单的IOC容器的实现,运行结果:

    Car [Carbrand=奔驰, wheel=Wheel [wheelBrand=米其林, width=50, height=50]]
    Wheel [wheelBrand=米其林, width=50, height=50]

    但是最简陋的IOC容器,随便考虑一下就还有非常多需要改进的地方还有非常的多

    AOP的简单实现

    AOP思想的实现原理是代理模式,简单AOP的容器先使用JDK中proxy类生成代理类

    通知

    通知有五种类型:

    1.前置通知  在目标方法执行前执行

    2.后置通知  在目标方法执行后执行,此时无关返回

    3.返回通知  在目标方法执行后执行

    4.异常通知  在目标方法抛出异常后执行通知

    5.环绕通知  目标方法被通知包裹,通知在方法执行前后都会执行

    切点

    如果说通知定义了在何时执行通知,那么切点就定义了在何处执行通知。所以切点的作用就是通过匹配规则查找合适的连接点(Joinpoint),AOP 会在这些连接点上织入通知。

    为了实现简单AOP,创建以下类

    MethodInvocation  实现了切面逻辑

    Advice  继承了invocationHandler接口

    BeforeAdvice  实现了Advice接口、

    SpringAop  生成代理类

    SpringAopTest  测试类

    HelloWord  目标方法接口

    HelloWordImpl  目标方法实现类

    MethodInvocation:

    public interface MethodInvocation {
        void invoke();
    }

    Advice:

    public interface Advice extends InvocationHandler {}

    beforeAdvice:

    public class BeforeAdvice implements Advice {
        private Object bean;
        private MethodInvocation methodInvocation;
    
        public BeforeAdvice(Object bean, MethodInvocation methodInvocation) {
            this.bean = bean;
            this.methodInvocation = methodInvocation;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 在目标方法执行前调用
            methodInvocation.invoke();
            return method.invoke(bean, args);//该方法表示执行被代理类原本的逻辑
       // 若在目标方法执行后调用,只需要将逻辑写在method.invoke之后
        }
    }

    SpringAop:

    public class SimpleAOP {
        public static Object getProxy(Object bean, Advice advice) {
            return Proxy.newProxyInstance(SimpleAOP.class.getClassLoader(), 
                    bean.getClass().getInterfaces(), advice);
        }
    }

    SpringAopTest:

    public class SimpleAOPTest {
        @Test
        public void getProxy() throws Exception {
            // 1. 创建一个 MethodInvocation 实现类
            MethodInvocation logTask = () -> System.out.println("log task start");
            HelloServiceImpl helloServiceImpl = new HelloServiceImpl();
            
            // 2. 创建一个 Advice
            Advice beforeAdvice = new BeforeAdvice(helloServiceImpl, logTask);
            
            // 3. 为目标对象生成代理
            HelloService helloServiceImplProxy = (HelloService) SimpleAOP.getProxy(helloServiceImpl,beforeAdvice);
            
            helloServiceImplProxy.sayHelloWorld();
        }
    }

    代理类及其实现:

    public interface HelloService {
        void sayHelloWorld();
    }
    
    public class HelloServiceImpl implements HelloService {
        @Override
        public void sayHelloWorld() {
            System.out.println("hello world!");
        }
    }
  • 相关阅读:
    查看crontab的日志记录定位定时任务问题
    Latex 表格内公式换行方法
    C语言中qsort函数用法
    7 种常用的排序算法-视觉直观感受
    Ubuntu下如何安装YouCompleteMe插件
    Linux下非root用户如何安装软件
    系统进化树-原理介绍及软件使用
    LaTeX 页眉页脚的设置
    TEXshade教程- 多重比对着色软件包
    easyUI自带的时间插件日期选择、月份选择、时间选择的使用
  • 原文地址:https://www.cnblogs.com/jinsheng1027/p/12131497.html
Copyright © 2020-2023  润新知