zoukankan      html  css  js  c++  java
  • spring原理解析

    关于spring,应该重点掌握的就是spring的两大特性,控制反转切面编程

    控制反转(IOC):

    ​ 在spring之前,我们创建对象都是自己手动new出来的,比如:

    User user = new User();
    

    ​ 这是之前我们创建对象的常用方式,而spring将这个过程进行了封装,帮我们创建对象,而我们需要使用的时候只需要去spring的容器中获取就可以了。

    UserDao userDao = (UserDao)BeanFactory.getBean(beanName:"userDao");
    

    看起来好像比之前的更复杂了,但是这样做却把程序间的耦合度降低了。

    这就是所谓的控制反转

    控制反转(IOC)

    那么spring是如何实现控制反转的呢?——反射

    控制反转实现原理

    利用反射机制创建对象

    //用于创建Bean对象
    public class BeanFactory {
        //定义一个Properties对象
        private static Properties pros;
        //定义一个Map,用于存放要创建的对象。称之为容器
        private static Map<String,Object> beans;
        //使用静态代码块为Properties赋值
        static{
            try {
                //实例化对象
                pros = new Properties();
                //获取Properties文件的流对象
                InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
                pros.load(in);
                //实例化容器
                beans = new HashMap<String, Object>();
                //取出配置文件中所有的key
                Enumeration keys = pros.keys();
                //遍历枚举类型
                while(keys.hasMoreElements()){
                    //取出每个key
                    String key = keys.nextElement().toString();
                    //获取key的value
                    String beanPath = pros.getProperty(key);
                    //通过反射创建对象
                    Object value = Class.forName(beanPath).newInstance();
                    //把bean和value存入容器之中
                    beans.put(key,value);
                }
            }catch(Exception e){
                throw new ExceptionInInitializerError("初始化properties失败");
            }
        }
    
        //根据bean名称获取bean对象
        public static Object getBean(String beanName) {
            //beans是一个map集合,里面存放了bean对象,单例
            return beans.get(beanName);
        }
    }
    

    读取配置文件,获取配置文件中key所对应的value,也就是类的全限定路径名,在通过反射机制创建出对象

    bean.properties:

    accoutService = cn.fzkj.service.Impl.AccoutServiceImpl
    accoutDao = cn.fzkj.dao.Impl.AccoutDaoImpl
    

    切面编程(AOP)

    基于代理思想,对原来的对象创建代理对象,从而在不改变原来代码的基础上对原有方法进行增强。

    主要的应用场景:

    • 记录日志
    • 性能监控
    • 权限控制
    • 缓存优化
    • 事务管理

    切面编程的实现原理

    spring中的切面编程的实现主要有两种方式:

    ​ 1.JDK动态代理

    ​ 2.Cglib动态代理

    - JDK动态代理

    代理类:

    public class Client {
        public static void main(String[] args) {
            final IProducer pro = new Producer();
            /**
             * 动态代理:
             *  特点:随用随创建,随用随加载
             *  作用:不修改源码的基础上对方法进行加强
             *  分类:
             *         1.基于接口
             *         2.基于子类
             *   基于接口的动态代理:
             *      涉及的类:Proxy
             *   创建代理对象:
             *          proxy类中的newProxyInstance方法
             *   创建代理的要求
             *          被代理类最少实现一个接口
             *    newProxyInstance的参数:
             *          ClassLoader:
             *              用于加载代理对象字节码,和被代理对象使用相同的类加载器
             *          class[]:字节码数组
             *              让代理对象和被代理对象有相同的方法
             *          InvocationHandler:用于提供增强的
             *              让我们写如何代理,一般写一个该接口的实现类,通常是匿名内部类
             *              此接口的实现类是谁用谁写
             */
            IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(pro.getClass().getClassLoader(),
                    pro.getClass().getInterfaces(),
                    new InvocationHandler() {
                    /**
                     * 作用:执行被代理对象的任何接口方法都会经过这个方法
                     * proxy:代理对象的引用
                     * method:当前执行的方法(描述对象)
                     *      method.invoke(被代理对象,实际参数)
                     * args:当前执行方法所需的参数
                     * 返回值:和被代理对象有相同的返回值
                     */
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //提供增强的代码
                            Object returnValue = null;
                            //1.获取方法执行的参数
                            Float money = (Float)args[0];
                            System.out.println("前置");
                            //2.判断当前执行的方法是否是销售
                            if("saleProduct".equals(method.getName())){
                                returnValue = method.invoke(pro,money*0.8f);
                            }
                            return returnValue;
                        }
                    });
            proxyProducer.saleProduct(10000f);
        }
    }
    

    service:

    public class Producer implements IProducer {
        //销售
        public void saleProduct(Float money) {
            System.out.println("拿到钱:"+money+",销售产品");
        }
        //售后
        public void afterService(Float money){
            System.out.println("提供售后,并拿到钱:"+money);
        }
    }
    

    运行结果:

    image-20200108135944083

    - Cglib动态代理

    代理类:

    public class Client {
        public static void main(String[] args) {
            final Producer pro = new Producer();
            /**
             * 动态代理:
             *  特点:随用随创建,随用随加载
             *  作用:不修改源码的基础上对方法进行加强
             *  分类:
             *         1.基于接口
             *         2.基于子类
             *   基于子类的动态代理:
             *      涉及的类:Enhancer
             *   创建代理对象:
             *          Enhancer类中的create方法
             *   创建代理的要求
             *          被代理类不能是最终类
             *    create的参数:
             *          Class:字节码
             *              指定被代理对象的字节码
             *          Callback:用于提供增强
             *              一半写的是该接口的子接口实现类
             */
            Producer cglibProducer = (Producer) Enhancer.create(pro.getClass(), new MethodInterceptor() {
                /**
                 * 执行被代理对象的方法都会经过这个方法
                 * @param proxy
                 * @param method
                 * @param args
                 * @param methodProxy :当前执行方法的代理对象
                 * @return
                 * @throws Throwable
                 */
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    //提供增强的代码
                            Object returnValue = null;
                            //1.获取方法执行的参数
                            Float money = (Float)args[0];
                    		System.out.println("前置");
                            //2.判断当前执行的方法是否是销售
                            if("saleProduct".equals(method.getName())){
                                returnValue = method.invoke(pro,money*0.8f);
                            }
                            return returnValue;
                }
            });
            cglibProducer.saleProduct(10000f);
        }
    }
    

    Producer类:

    public class Producer {
        //销售
        public void saleProduct(Float money) {
            System.out.println("拿到钱:"+money+",销售产品");
        }
        //售后
        public void afterService(Float money){
            System.out.println("提供售后,并拿到钱:"+money);
        }
    }
    

    运行结果:

    spring的ioc和aop就结束了。

    扩展:

    aop中代理的实现,即spring是如何给目标对象创建代理类的

    一个主方法:

    public class Client {
        public static void main(String[] args) {
            final Producer pro = new Producer();
            Producer p = (Producer) new CglibProxyFactory(pro).getProxyInstance();
            p.saleProduct(10000f);
        }
    }
    

    可以看出,通过CglibProxyFactory类的getProxyInstance()方法得到的就是一个代理对象。

    CglibProxyFactory类:

    //创建代理类
    public class CglibProxyFactory {
        //初始化对象
        private Object target;
        public CglibProxyFactory(Object target){
            this.target = target;
        }
        //创建代理对象
        public Object getProxyInstance(){
            return Enhancer.create(target.getClass(), new MethodInterceptor() {
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    System.out.println("开始事务");
                    Float money = (Float)args[0];
                    Object returnValue = method.invoke(target, money*0.8f);
                    System.out.println("提交事务");
                    return returnValue;
                }
            });
        }
    }
    

    运行结果:

    image-20200108141232177


    持续更新~~~

  • 相关阅读:
    CentOS6.5 [ERROR] /usr/libexec/mysqld: Can't create/write to file '/var/lib/mysqld/mysqld.pid' (Errcode: 2)
    linux防火墙
    Linux磁盘分区与LVM详解
    LVM分区扩展空间
    linux 分区方法(超过2T的硬盘)
    linux异常处理:selinux配置错误导致无法重启
    linux网卡配置文件
    Zabbix4.0系统clone、mass update使用
    Zabbix系统配置日志监控告警--关键字触发
    Zabbix4.0系统配置事件通知
  • 原文地址:https://www.cnblogs.com/mrjkl/p/13052139.html
Copyright © 2011-2022 走看看