zoukankan      html  css  js  c++  java
  • 【一步一步学习spring】spring aop 底层实现

    1. JDK的动态代理

    注意一下:该动态代理只能对实现了接口的类进行代理!

    使用动态代理的五大步骤

    • 通过实现InvocationHandler接口来自定义自己的InvocationHandler;
    • 通过Proxy.getProxyClass获得动态代理类
    • 通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
    • 通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
    • 通过代理对象调用目标方法

    DEMO

    package com.aop.demo1;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyTest {
    	public interface IHello {
    		void sayHello();
    	}
    
    	static class Hello implements IHello {
    		public void sayHello() {
    			System.out.println("Hello world!!");
    		}
    	}
    
    	// 自定义InvocationHandler
    	static class HWInvocationHandler implements InvocationHandler {
    		// 目标对象
    		private Object target;
    
    		public HWInvocationHandler(Object target) {
    			this.target = target;
    		}
    
    		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    			System.out.println("------插入前置通知代码-------------");
    			// 执行相应的目标方法
    			Object rs = method.invoke(target, args);
    			System.out.println("------插入后置处理代码-------------");
    			return rs;
    		}
    	}
    
    	public static void main(String[] args)
    			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    		IHello ihello = (IHello) Proxy.newProxyInstance(Hello.class.getClassLoader(), Hello.class.getInterfaces(), // 一组接口
    				new HWInvocationHandler(new Hello())); // 自定义的InvocationHandler
    		ihello.sayHello();
    	}
    }
    

    2. CGLIB生成代理

    • 对于不使用接口的业务类,无法使用JDK动态代理
    • CGLIB采用非常底层字节码技术,可以为一个类创建子类,解决无接口的代理问题

    使用CGlib代理的四大步骤

    • 创建Enhancer核心类
    • 设置父类为目标类
    • 设置回调,其中实现具体要增强的逻辑
    • 生成代理

    DEMO

    package com.aop.demo1;
    
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    public class CglibTest {
        public void test(){
            System.out.println("hello world");
        }
    
        public static void main(String[] args) {
        	// 1.创建核心类
            Enhancer enhancer = new Enhancer();
            // 2.设置父类
            enhancer.setSuperclass(CglibTest.class);
            // 3.设置回调
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    System.out.println("before method run...");
                    Object result = proxy.invokeSuper(obj, args);
                    System.out.println("after method run...");
                    return result;
                }
            });
            // 4.生成代理
            CglibTest sample = (CglibTest) enhancer.create();
            sample.test();
        }
    }
    

    3. 总结

    • spring在运行期,生成动态代理对象,不需要特殊的编译器
    • spring aop的底层就是通过jdk动态代理或cglib动态代理技术为目标Bean执行横向织入
      • 若目标对象实现了接口,spring使用jdk的java.lang.reflect.Proxy类代理
      • 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
    • 应该优先对接口创建代理,便于程序解耦维护
    • 标记为final的方法不能被代理。
    • spring只支持方法连接点,不提供属性连接点
    • 优缺点:
      • CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,
      • 但是CGLib在创建代理对象时所花费的时间却比JDK多得多,
      • 所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
  • 相关阅读:
    window忘记密码怎么办
    VS2015配置Andriod开发环境
    记一次 thread.blocked.count 线程过多的问题排查
    Spring的事务初见
    对mybatis的Handler 从使用角度介绍
    最简单的RPC框架实现
    记一次mybatis bindingexception 问题排查
    Java线程池—ThreadPool简介
    [springMvc] 源码分析笔记(二)
    [tomcat] tomcat简析(一)
  • 原文地址:https://www.cnblogs.com/xxxuwentao/p/9593856.html
Copyright © 2011-2022 走看看