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


持续更新~~~

posted @ 2020-06-05 20:23  杨欢喜e  阅读(305)  评论(0编辑  收藏  举报