精华内容
下载资源
问答
  • 2021-03-26 20:54:12

    注:这里不阐述Spring和AOP的一些基本概念和用法,直接进入正题。另外,在spring中创建AOP代理严格说来有两个地方,一个是本文提及的初始化之后的后置处理器,还有一个是三级缓存,这个解决了单例对象循环依赖的时候存在AOP的问题,本文对此暂不提及,在后面讲述spring多级缓存和循环依赖的时候再进行详细说明~

    流程

      Spring所管理的对象大体会经过确定实例化对象类型、推断构造方法创建对象(实例化)、设置属性、初始化等等步骤。在对象初始化阶段,Spring为开发者提供了一个BeanPostProcessor接口,它会在对象初始化之前和初始化之后被调用(初始化,不是实例化,对应实例化的是InstantiationAwareBeanPostProcessor接口)。

    public interface BeanPostProcessor {
    	//初始化之前
    	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    	//初始化之后
    	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    
    }
    

      在对象初始化之后会调用postProcessAfterInitialization方法,该方法返回一个Object。如果成功返回了一个对象,那么容器中相应beanName对应的实例就将会是这个对象。
      本文主要分析动态代理,我们着重看AnnotationAwareAspectJAutoProxyCreator。先来看一下它的继承关系:
    在这里插入图片描述  AnnotationAwareAspectJAutoProxyCreator最终实现了BeanPostProcessor接口(也实现了InstantiationAwareBeanPostProcessor接口),可以看到继承关系比较复杂。当前我们关注的postProcessAfterInitialization方法实现在它的父类AbstractAutoProxyCreator中(只保留了部分代码):

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		if (bean != null) {
    			Object cacheKey = getCacheKey(bean.getClass(), beanName);
    			if (!this.earlyProxyReferences.contains(cacheKey)) {
    				return wrapIfNecessary(bean, beanName, cacheKey);
    			}
    		}
    		return bean;
    	}
    

      这里主要看看wrapIfNecessary方法(只保留了部分代码):

    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		......
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		if (specificInterceptors != DO_NOT_PROXY) {
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
    			Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    		......
    }
    

      其中核心的是两个方法调用,分别是getAdvicesAndAdvisorsForBean和createProxy。getAdvicesAndAdvisorsForBean会返回一个对象数组,包含aop相关的一些对象,如果是一个普通的不需要代理的对象会返回一个空Object数组,也就是DO_NOT_PROXY;createProxy方法则是创建代理类。
      先看看getAdvicesAndAdvisorsForBean方法:

    protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;
    

      getAdvicesAndAdvisorsForBean方法在当前类(AbstractAutoProxyCreator)中是一个抽象方法,由子类AbstractAdvisorAutoProxyCreator实现:

    public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
    	@Override
    	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
    		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    		if (advisors.isEmpty()) {
    			return DO_NOT_PROXY;
    		}
    		return advisors.toArray();
    	}
    }
    

      代码很清晰,我们进入findEligibleAdvisors方法,看方法名也知道它会完成寻找Advisor的工作:

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    		//寻找Advisor
    		List<Advisor> candidateAdvisors = findCandidateAdvisors();
    		//针对指定的bean,过滤可用的Advisor,比如根据注解匹配
    		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    		extendAdvisors(eligibleAdvisors);
    		if (!eligibleAdvisors.isEmpty()) {
    			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    		}
    		return eligibleAdvisors;
    	}
    

      首先进入findCandidateAdvisors方法:

    protected List<Advisor> findCandidateAdvisors() {
    		// Add all the Spring advisors found according to superclass rules.
    		List<Advisor> advisors = super.findCandidateAdvisors();
    		// Build Advisors for all AspectJ aspects in the bean factory.
    		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    		return advisors;
    	}
    

      我们这里主要看看aspectj的逻辑,所以看看aspectJAdvisorsBuilder.buildAspectJAdvisors方法(只保留了主要代码):

    public List<Advisor> buildAspectJAdvisors() {
    		List<String> aspectNames = null;
    		......
    		synchronized (this) {
    			aspectNames = this.aspectBeanNames;
    			if (aspectNames == null) {
    				//获取所有管理的beanName
    				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
    				//遍历每个beanName
    				for (String beanName : beanNames) {
    					//从beanFactory获取Class
    					Class<?> beanType = this.beanFactory.getType(beanName);
    					//检查对应的Class是否实现Aspect注解
    					if (this.advisorFactory.isAspect(beanType)) {
    						//说明这个beanName对应的类是一个切面	
    						aspectNames.add(beanName);
    						AspectMetadata amd = new AspectMetadata(beanType, beanName);
    						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
    							MetadataAwareAspectInstanceFactory factory =
    									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
    							//获取Advisor,主要是解析对象中关于AOP的注解,比如Pointcut
    							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    							if (this.beanFactory.isSingleton(beanName)) {
    								//就放入缓存,后面就不用重新解析了
    								this.advisorsCache.put(beanName, classAdvisors);
    							}
    							advisors.addAll(classAdvisors);
    						}
    					}
    				}
    				this.aspectBeanNames = aspectNames;
    				return advisors;
    			}
    		}
    	......
    }
    

      会从beanFactory中寻找所有管理的beanName,返回一个String数组,然后遍历数组,从beanFactory中根据beanName获取对应的Class,然后再看对应的Class是否有Aspect注解,如果有对应的注解,那么就表示这个对象是一个切面。接下来就需要进行解析,生成真正的Advisor对象,最后放入缓存。
      可以看看isAspect方法是如何判断的:

    @Override
    	public boolean isAspect(Class<?> clazz) {
    		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
    	}
    	private boolean hasAspectAnnotation(Class<?> clazz) {
    		return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
    	}
    

      逻辑很清晰,主要就是看有没有Aspect注解。再回到findEligibleAdvisors方法,上面代码已经贴了,这里就不贴了。获取到Advisor列表之后,要从中找到能用于指定类的Advisor列表,然后返回。接下来就要为指定的对象创建代理对象了,也就是AbstractAutoProxyCreator类的createProxy方法:

    	protected Object createProxy(
    			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
    		ProxyFactory proxyFactory = new ProxyFactory();
    		proxyFactory.copyFrom(this);
    
    		if (!proxyFactory.isProxyTargetClass()) {
    			if (shouldProxyTargetClass(beanClass, beanName)) {
    				proxyFactory.setProxyTargetClass(true);
    			}
    			else {
    				evaluateProxyInterfaces(beanClass, proxyFactory);
    			}
    		}
    
    		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    		for (Advisor advisor : advisors) {
    			proxyFactory.addAdvisor(advisor);
    		}
    
    		proxyFactory.setTargetSource(targetSource);
    		customizeProxyFactory(proxyFactory);
    
    		proxyFactory.setFrozen(this.freezeProxy);
    		if (advisorsPreFiltered()) {
    			proxyFactory.setPreFiltered(true);
    		}
    
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}
    

      代理对象是由ProxyFactory代理工厂创建的,我们先看看这个工厂是如何创建代理对象的,也就是proxyFactory.getProxy方法:

    public Object getProxy(ClassLoader classLoader) {
    	return createAopProxy().getProxy(classLoader);
    }
    

      createAopProxy方法会返回一个AopProxy,该方法定义在ProxyFactory的父类ProxyCreatorSupport中:

    public class ProxyCreatorSupport extends AdvisedSupport {
    	private AopProxyFactory aopProxyFactory;
    	public ProxyCreatorSupport() {
    		//设置默认的代理工厂DefaultAopProxyFactory
    		this.aopProxyFactory = new DefaultAopProxyFactory();
    	}
    	public AopProxyFactory getAopProxyFactory() {
    		//获取代理工厂,默认就是DefaultAopProxyFactory
    		return this.aopProxyFactory;
    	}
    
    	protected final synchronized AopProxy createAopProxy() {
    		//先获取代理工厂,然后调用工厂的createAopProxy方法创建AopProxy
    		return getAopProxyFactory().createAopProxy(this);
    	}
    }
    

      上面贴出了关键代码,getAopProxyFactory默认返回的是一个DefaultAopProxyFactory工厂类,来看看DefaultAopProxyFactory的createAopProxy方法:

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    			Class<?> targetClass = config.getTargetClass();
    			if (targetClass.isInterface()) {
    				return new JdkDynamicAopProxy(config);
    			}
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}
    

      代码中有一些代理配置的判断,这里不用关心。可以看到它提供了两个AopProxy,分别是基于JDK的JdkDynamicAopProxy和基于cglib的ObjenesisCglibAopProxy。由于JDK提供的动态代理实现最终生成的代理类默认会继承Proxy类,实现被代理类实现的接口,因为Java是单继承,所以只能通过接口实现,也就限制了要使用JDK提供的动态代理,必须要基于接口。而使用cglib基于字节码的改造则没有这个限制,所以Spring提供了这两种方式,根据被代理类的实际情况来选择。
      关于每个AopProxy是如何创建代理类的,这里就先不跟了~

    总结

      总的来说,动态代理是实现AOP的重要手段,Spring提供的动态代理主要依靠其提供的BeanPostProcessor,也称之为后置处理器。除了BeanPostProcessor之外,还有InstantiationAwareBeanPostProcessor(也继承了BeanPostProcessor),它们会在bean的生命周期的特定阶段被调用,以开放给开发者处理和调整对象的入口或者手段。动态代理依托后置处理器,在后置处理器的逻辑中使用AopProxy创建了被代理对象的代理类,然后代替原有类存入Spring的bean工厂中,之后根据beanName获取的实例对象就不再是原对象实例,而是代理类。而AopProxy是由AopProxyFactory接口生成,目前该接口只有DefaultAopProxyFactory实现类,其提供了两种AopProxy,分别基于原生JDK提供的动态代理和cgib,根据实际情况选择。
    在这里插入图片描述
      本文简单跟踪了一下普遍情况下的动态代理实现,但是关于Spring动态代理还有很多细节,比如,除了基于Aspect注解,Spring还提供了些什么方式实现动态代理?Spring是如何集成Aspect的?基于JDK实现的动态代理和CGLIB实现的动态代理有何区别?如何处理方法嵌套调用?@Bean注解的方法嵌套调用如何保证单例?文中提到的有两个地方创建动态代理,三级缓存是如何使用的?如果有多个Pointcut命中了被代理对象,Advice是怎样的调用顺序?等等等等~ 本文只当是一个通常情况下动态代理实现的一个基础介绍,后面会针对这一块做一个完整的源码分析~

    更多相关内容
  • 细说Spring——AOP详解(动态代理实现AOP)

    千次阅读 多人点赞 2018-06-05 21:25:11
    前言 嗯,我应该是有一段实现没有写...决定还是要克服困难,我仔细的想了一下怎么讲解AOP实现这一部分,然后我决定由浅入深的讲解动态代理,然后用动态代理实现一个简单的AOP,感觉这样能够让人对AOP的原理有一个比...

    前言

    嗯,我应该是有一段实现没有写过博客了,在写完了细说Spring——AOP详解(AOP概览)之后,我发现我不知道该怎么写AOP这一部分,所以就把写博客这件事给放下了,但是这件事情又不想就这么放弃,所以今天我仔细思考了一下,决定还是要克服困难,我仔细的想了一下怎么讲解AOP实现这一部分,然后我决定由浅入深的讲解动态代理,然后用动态代理实现一个简单的AOP,感觉这样能够让人对AOP的原理有一个比较深刻的认识,希望能帮到大家。而且最近学习又组建了ACM比赛的队伍,虽然已经要大三了,按理来说应该一心学习Java Web的开发,可是我对算法也有一定的兴趣,并且之前也确实花过一段时间练习算法题,所以还是决定要参加一下,所以写博客可能就会慢一点吧。

    一、什么是动态代理

    动态代理其实就是Java中的一个方法,这个方法可以实现:动态创建一组指定的接口的实现对象(在运行时,创建实现了指定的一组接口的对象)
    这里声明一下,本篇博客中会使用很多AOP中的术语,所以如果看不懂术语的话一定要先看一下细说Spring——AOP详解(AOP概览)
    例如:

    interface A {}
    interface B {}
    //obj对象的类型实现了A和B两个接口
    Object obj = 方法(new Class[]{A.class, B.class})

    二、动态代理初体验

    我们根据上面的思路来体验一下Java中的动态代理吧,首先我们要先写两个接口。

    interface A {
        public void a();
    }
    interface B {
        public void b();
    }

    然后我们就先来看一下动态代理的代码:

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

    上面这个就是动态代理类(Proxy)类中的创建代理对象的方法,下面介绍一下方法的三个参数:

    • ClassLoader loader:方法需要动态生成一个类,这个类实现了A和B两个接口,然后创建这个类的对象。需要生成一个类,而且这个类也需要加载到方法区中,所以我们需要一个ClassLoader来加载该类
    • Class<?>[] interfaces:我们需要代理对象实现的数组
    • InvocationHandler h:调用处理器

    这里你可能对InvocationHandler有疑惑,这里先买个关子,下面马上揭晓。
    我们现在就使用动态代理创建一个代理对象吧。

    @Test
        public void test1() {
            /**
             * 三个参数
             * 1、ClassLoader
             * 方法需要动态生成一个类,这个类实现了A和B两个接口,然后创建这个类的对象
             * 需要生成一个类,这个类也需要加载到方法区中,所以我们需要一个ClassLoader来加载该类
             *
             * 2、Class[] interfaces
             * 我们需要代理对象实现的数组
             *
             * 3、InvocationHandler
             * 调用处理器
             */
            ClassLoader classLoader = this.getClass().getClassLoader();
            //这里创建一个空实现的调用处理器。
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    return null;
                }
            };
            Object obj = Proxy.newProxyInstance(classLoader, new Class[]{A.class, B.class}, invocationHandler);
            //强转为A和B接口类型,说明生成的代理对象实现了A和B接口
            A a = (A) obj;
            B b = (B) obj;
        }

    经过测试代码运行成功,说明生成的代理对象确实实现了A接口和B接口,但是我想你一定会对代理对象如何实现了A接口和B接口感兴趣,你一定想知道如果使用代理对象调用相应接口的方法会发生什么感兴趣,下面我们一起来探究一下:

    上面代码的基础上加上下面的代码
    a.a();
    b.b(); 

    这里写图片描述
    我们可以发现什么也没有发生。这是因为我们根本没有为代理对象添加实现逻辑。可是实现逻辑添加在哪里呢?哈哈,当然是InvocationHandler中了。下面就看一看添加了实现逻辑的代码:

     @Test
        public void test2() {
            /**
             * 三个参数
             * 1、ClassLoader
             * 方法需要动态生成一个类,这个类实现了A和B两个接口,然后创建这个类的对象
             * 需要生成一个类,这个类也需要加载到方法区中,所以我们需要一个ClassLoader来加载该类
             *
             * 2、Class[] interfaces
             * 我们需要代理对象实现的数组
             *
             * 3、InvocationHandler
             * 调用处理器
             *
             * 代理对象实现的所有接口中的方法,内容都是调用InvocationHandler的invoke()方法
             */
            ClassLoader classLoader = this.getClass().getClassLoader();
            //这里创建一个空实现的调用处理器。
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("你好!!!!");//注意这里添加了一点小逻辑
                    return null;
                }
            };
            Object obj = Proxy.newProxyInstance(classLoader, new Class[]{A.class, B.class}, invocationHandler);
            //强转为A和B接口类型,说明生成的代理对象实现了A和B接口
            A a = (A) obj;
            B b = (B) obj;
    
            a.a();
            b.b();
        }

    截图如下:
    这里写图片描述
    这里我们发现A接口和B接口的实现逻辑都是调用了invoke这个方法中的逻辑,其实除了调用代理对象的native方法,调用代理对象的其他所有方法本质都是调用了invoke方法,下面我们再来看第三个实例,让我们对动态代理有更深刻的认识。

    public void test3() {
            /**
             * 三个参数
             * 1、ClassLoader
             * 方法需要动态生成一个类,这个类实现了A和B两个接口,然后创建这个类的对象
             * 需要生成一个类,这个类也需要加载到方法区中,所以我们需要一个ClassLoader来加载该类
             *
             * 2、Class[] interfaces
             * 我们需要代理对象实现的数组
             *
             * 3、InvocationHandler
             * 调用处理器
             *
             * 代理对象实现的所有接口中的方法,内容都是调用InvocationHandler的invoke()方法
             */
            ClassLoader classLoader = this.getClass().getClassLoader();
            //这里创建一个空实现的调用处理器。
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("你好!!!!");
                    return "Hello";//这里改为返回"Hello"
                }
            };
            Object obj = Proxy.newProxyInstance(classLoader, new Class[]{A.class, B.class}, invocationHandler);
            //强转为A和B接口类型,说明生成的代理对象实现了A和B接口
            A a = (A) obj;
            B b = (B) obj;
            a.toString();//注意这里调用了toString()方法
            b.getClass();//注意这里调用了getClass()方法
            //这里在A接口中添加了一个方法public Object aaa(String s1, int i);
            Object hello = a.aaa("Hello", 100);
            System.out.println(obj.getClass());//这里看一下代理对象是什么
            System.out.println(hello);//这里看一下返回值是什么
    
        }

    这里写图片描述
    通过代码的结果我们大胆的猜测一下,代理对象方法的返回值其实就是invoke方法的返回值,代理对象其实就是使用反射机制实现的一个运行时对象。哈哈,当然这些肯定不是猜测了,其实确实就是这样。下面是时候总结一下InvocationHandlerinvoke方法了。如下图所示:
    这里写图片描述
    当我们调用代理对象的方法时,其对应关系就如上图所示。

    三、初步实现AOP

    在我们对动态代理有了一定的认识之后,我们就可以实现最基本版本的AOP了,当然,这是一个非常残缺的AOP实现,甚至都不能称之为AOP实现。
    我们先写一个接口:

    package demo2;
    
    /**
     * Created by Yifan Jia on 2018/6/5.
     */
    //服务生
    public interface Waiter {
        //服务方法
        public void server();
    }

    然后给出该接口的实现类:

    package demo2;
    
    /**
     * Created by Yifan Jia on 2018/6/5.
     */
    public class ManWaiter implements Waiter {
    
        @Override
        public void server() {
            System.out.println("服务中");
        }
    }
    

    然后我们就通过动态代理来对上面的ManWaiter进行增强:

    package demo2;
    
    import org.junit.Test;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * Created by Yifan Jia on 2018/6/5.
     */
    
    public class Demo2 {
        @Test
        public void test1() {
            Waiter waiter = new ManWaiter();
            waiter.server();
        }
    
        @Test
        public void test2() {
            Waiter manWaiter = new ManWaiter();
            ClassLoader classLoader = this.getClass().getClassLoader();
            Class[] interfaces = {Waiter.class};
            InvocationHandler invocationHandler = new WaiterInvocationHandler(manWaiter);
            //得到代理对象,代理对象就是在目标对象的基础上进行了增强的对象
            Waiter waiter = (Waiter) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
            waiter.server();//前面添加“你好”,后面添加“再见”
        }
    }
    
    class WaiterInvocationHandler implements InvocationHandler {
    
        private Waiter waiter;
    
        WaiterInvocationHandler(Waiter waiter) {
            this.waiter = waiter;
        }
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("你好");
            waiter.server();//调用目标对象的方法
            System.out.println("再见");
            return null;
        }
    }
    

    结果如下:
    这里写图片描述
    你肯定要说了,这算什么AOP,增强的代码都是硬编码到invoke方法中的,大家稍安勿躁,我们不是已经对需要增强的对象做了增强吗。这里可以的目标对象为manWaiter,增强为System.out.println("你好");System.out.println("再见");,切点为server()方法调用。其实还是可以看做一下原始的AOP的。

    四、完善的AOP实现

    我们从初步实现的AOP中可以发现很多问题,比如我们不能把增强的逻辑硬编码到代码中,我们需要实现可变的增强,下面我们就解决一下这些问题,来实现一个比较完善的AOP。
    我们仍然引用上面的Waiter接口和Manwaiter实现类。
    然后我们添加一个前置增强接口:

    /**
     * 前置增强
     */
    public interface BeforeAdvice {
        public void before();
    }

    再添加一个后置增强接口:

    public interface AfterAdvice {
        public void after();
    }

    我们把产生代理对象的代码封装为一个类:

    package demo3;
    
    import com.sun.org.apache.regexp.internal.RE;
    import org.junit.After;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * ProxFactory用来生成代理对象
     * 它需要所有的参数:目标对象,增强,
     * Created by Yifan Jia on 2018/6/5.
     */
    
    /**
     * 1、创建代理工厂
     * 2、给工厂设置目标对象、前置增强、后置增强
     * 3、调用creatProxy()得到代理对象
     * 4、执行代理对象方法时,先执行前置增强,然后是目标方法,最后是后置增强
     */
    //其实在Spring中的AOP的动态代理实现的一个织入器也是叫做ProxyFactory 
    public class ProxyFactory {
        private Object targetObject;//目标对象
        private BeforeAdvice beforeAdvice;//前值增强
        private AfterAdvice afterAdvice;//后置增强
    
        /**
         * 用来生成代理对象
         * @return
         */
        public Object creatProxy() {
            /**
             * 给出三个参数
             */
            ClassLoader classLoader = this.getClass().getClassLoader();
            //获取当前类型所实现的所有接口类型
            Class[] interfaces = targetObject.getClass().getInterfaces();
    
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    /**
                     * 在调用代理对象的方法时,会执行这里的内容
                     */
                    if(beforeAdvice != null) {
                        beforeAdvice.before();
                    }
                    Object result = method.invoke(targetObject, args);//调用目标对象的目标方法
                    //执行后续增强
                    afterAdvice.after();
    
                    //返回目标对象的返回值
                    return result;
                }
            };
            /**
             * 2、得到代理对象
             */
            Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
            return proxyObject;
    
        }
    //get和set方法略
    }
    

    然后我们将相关的参数注入到ProxyFactory后就可以通过creatProxy()方法获取代理对象了,代码如下:

    package demo3;
    
    import org.junit.Test;
    
    /**
     * Created by Yifan Jia on 2018/6/5.
     */
    public class Demo3 {
        @Test
        public void tset1() {
    
            ProxyFactory proxyFactory = new ProxyFactory();//创建工厂
            proxyFactory.setTargetObject(new ManWaiter());//设置目标对象
            //设置前置增强
            proxyFactory.setBeforeAdvice(new BeforeAdvice() {
                @Override
                public void before() {
                    System.out.println("客户你好");
                }
            });
            //设置后置增强
            proxyFactory.setAfterAdvice(new AfterAdvice() {
                @Override
                public void after() {
                    System.out.println("客户再见");
                }
            });
            Waiter waiter = (Waiter) proxyFactory.creatProxy();
            waiter.server();
    
        }
    }
    

    结果如下:
    这里写图片描述
    这时候我们已经可以自定义任意的增强逻辑了,是不是很神奇。

    五、动态代理实现AOP总结

    通过上面的内容,我们已经通过动态代理实现了一个非常简陋的AOP,这里的AOP实现还是有很多的不足之处。下面我把Spring中的ProxyFactory实现贴出来,大家可以研究一下Spring中的ProxyFactory的优势在哪里,另外,Spring中还有其他的基于动态代理实现的织入器,ProxyFactory只是其中最基础的版本,大家有兴趣可以研究一下。

    public class ProxyFactory extends ProxyCreatorSupport {
        public ProxyFactory() {
        }
    
        public ProxyFactory(Object target) {
            Assert.notNull(target, "Target object must not be null");
            this.setInterfaces(ClassUtils.getAllInterfaces(target));
            this.setTarget(target);
        }
    
        public ProxyFactory(Class... proxyInterfaces) {
            this.setInterfaces(proxyInterfaces);
        }
    
        public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
            this.addInterface(proxyInterface);
            this.addAdvice(interceptor);
        }
    
        public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
            this.addInterface(proxyInterface);
            this.setTargetSource(targetSource);
        }
    
        public Object getProxy() {
            return this.createAopProxy().getProxy();
        }
    
        public Object getProxy(ClassLoader classLoader) {
            return this.createAopProxy().getProxy(classLoader);
        }
    
        public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {
            return (new ProxyFactory(proxyInterface, interceptor)).getProxy();
        }
    
        public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {
            return (new ProxyFactory(proxyInterface, targetSource)).getProxy();
        }
    
        public static Object getProxy(TargetSource targetSource) {
            if(targetSource.getTargetClass() == null) {
                throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
            } else {
                ProxyFactory proxyFactory = new ProxyFactory();
                proxyFactory.setTargetSource(targetSource);
                proxyFactory.setProxyTargetClass(true);
                return proxyFactory.getProxy();
            }
        }
    }
    展开全文
  • Android 动态代理以及利用动态代理实现 ServiceHook

    万次阅读 多人点赞 2017-02-25 20:44:15
    Android 利用 ServiceHook 实现特殊功能

      这篇博客主要介绍使用 InvocationHandler 这个接口来达到 hook 系统 service ,从而实现一些很有意思特殊功能的详细步骤。
      转载请注明出处:http://blog.csdn.net/self_study/article/details/55050627
      对技术感兴趣的同鞋加群 544645972 一起交流。
      相关博客介绍:
      android 不能在子线程中更新ui的讨论和分析:Activity 打开的过程分析;
      java/android 设计模式学习笔记(9)—代理模式:AMS 的相关类图和介绍;
      android WindowManager解析与骗取QQ密码案例分析:界面 window 的创建过程;
      java/android 设计模式学习笔记(8)—桥接模式:WMS 的相关类图和介绍;
      android IPC通信(下)-AIDL:AIDL 以及 Binder 的相关介绍;
      Android 动态代理以及利用动态代理实现 ServiceHook:ServiceHook 的相关介绍;
      Android TransactionTooLargeException 解析,思考与监控方案:TransactionTooLargeException 的解析以及监控方案。  

    Java 的动态代理

      首先我们要介绍的就是 Java 动态代理,Java 的动态代理涉及到两个类:InvocationHandler 接口和 Proxy 类,下面我们会着重介绍一下这两个类,并且结合实例来着重分析一下使用的正确姿势等。在这之前简单介绍一下 Java 中 class 文件的生成和加载过程,Java 编译器编译好 Java 文件之后会在磁盘中产生 .class 文件。这种 .class 文件是二进制文件,内容是只有 JVM 虚拟机才能识别的机器码,JVM 虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析 .class 文件内的信息,使用相对应的 ClassLoader 类加载器生成对应的 Class 对象:
    这里写图片描述
    .class 字节码文件是根据 JVM 虚拟机规范中规定的字节码组织规则生成的,具体的 .class 文件格式介绍可以查看博客 深入理解Java Class文件格式Java 虚拟机规范
      通过上面我们知道 JVM 是通过字节码的二进制信息加载类的,那么我们如果在运行期系统中,遵循 Java 编译系统组织 .class 文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据转换成对应的类,这样就可以在运行中动态生成一个我们想要的类了:
    这里写图片描述
      Java 中有很多的框架可以在运行时根据 JVM 规范动态的生成对应的 .class 二进制字节码,比如 ASM 和 Javassist 等,这里就不详细介绍了,感兴趣的可以去查阅相关的资料。这里我们就以动态代理模式为例来介绍一下我们要用到这两个很重要的类,关于动态代理模式,我在 java/android 设计模式学习笔记(9)—代理模式中已经介绍过了,但是当时并没有详细分析过 InvocationHandler 接口和 Proxy 类,这里就来详细介绍一下。在代理模式那篇博客中,我们提到了代理模式分为动态代理和静态代理:
    这里写图片描述
    上面就是静态代理模式的类图,当在代码阶段规定这种代理关系时,ProxySubject 类通过编译器生成 .class 字节码文件,当系统运行之前,这个 .class 文件就已经存在了。动态代理模式的结构和上面的静态代理模式的结构稍微有所不同,它引入了一个 InvocationHandler 接口和 Proxy 类。在静态代理模式中,代理类 ProxySubject 中的方法,都指定地调用到特定 RealSubject 中对应的方法,ProxySubject 所做的事情无非是调用触发 RealSubject 对应的方法;动态代理工作的基本模式就是将自己方法功能的实现交给 InvocationHandler 角色,外界对 Proxy 角色中每一个方法的调用,Proxy 角色都会交给 InvocationHandler 来处理,而 InvocationHandler 则调用 RealSubject 的方法,如下图所示:这里写图片描述

    InvocationHandler 接口和 Proxy

      我们来分析一下动态代理模式中 ProxySubject 的生成步骤:

    1. 获取 RealSubject 上的所有接口列表;
    2. 确定要生成的代理类的类名,系统默认生成的名字为:com.sun.proxy.$ProxyXXXX ;
    3. 根据需要实现的接口信息,在代码中动态创建该 ProxySubject 类的字节码;
    4. 将对应的字节码转换为对应的 Class 对象;
    5. 创建 InvocationHandler 的实例对象 h,用来处理 Proxy 角色的所有方法调用;
    6. 以创建的 h 对象为参数,实例化一个 Proxy 角色对象。
    具体的代码为:

    Subject.java

    public interface Subject {
        String operation();
    }

    RealSubject.java

    public class RealSubject implements Subject{
        @Override
        public String operation() {
            return "operation by subject";
        }
    }

    ProxySubject.java

    public class ProxySubject implements InvocationHandler{
         protected Subject subject;
        public ProxySubject(Subject subject) {
            this.subject = subject;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //do something before
            return method.invoke(subject, args);
        }
    }

    测试代码

    Subject subject = new RealSubject();
    ProxySubject proxy = new ProxySubject(subject);
    Subject sub = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
            subject.getClass().getInterfaces(), proxy);
    sub.operation();

    以上就是动态代理模式的最简单实现代码,JDK 通过使用 java.lang.reflect.Proxy 包来支持动态代理,我们来看看这个类的表述:

    Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the 
    superclass of all dynamic proxy classes created by those methods.

    一般情况下,我们使用下面的

    public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException { 
        // 检查 h 不为空,否则抛异常
        if (h == null) { 
            throw new NullPointerException(); 
        } 
    
        // 获得与指定类装载器和一组接口相关的代理类类型对象
        Class cl = getProxyClass(loader, interfaces); 
    
        // 通过反射获取构造函数对象并生成代理类实例
        try { 
            Constructor cons = cl.getConstructor(constructorParams); 
            return (Object) cons.newInstance(new Object[] { h }); 
        } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); 
        } catch (IllegalAccessException e) { throw new InternalError(e.toString()); 
        } catch (InstantiationException e) { throw new InternalError(e.toString()); 
        } catch (InvocationTargetException e) { throw new InternalError(e.toString()); 
        } 
    }

    Proxy 类的 getProxyClass 方法调用了 ProxyGenerator 的 generatorProxyClass 方法去生成动态类:

    public static byte[] generateProxyClass(final String name, Class[] interfaces)

    这个方法我们下面将会介绍到,这里先略过,生成这个动态类的字节码之后,通过反射去生成这个动态类的对象,通过 Proxy 类的这个静态函数生成了一个动态代理对象 sub 之后,调用 sub 代理对象的每一个方法,在代码内部,都是直接调用了 InvocationHandler 的 invoke 方法,而 invoke 方法根据代理类传递给自己的 method 参数来区分是什么方法,我们来看看 InvocationHandler 类的介绍:

    InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
    
    Each proxy instance has an associated invocation handler. When a method is invoked on a proxy 
    instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
    Public methods
    abstract Objectinvoke(Object proxy, Method method, Object[] args)Processes a method invocation on a proxy instance and returns the result.

    方法的参数和返回:

    Parameters
    proxyObject: the proxy instance that the method was invoked on
    methodMethod: the Method instance corresponding to the interface method invoked on the proxy instance. The declaring class of the Method object will be the interface that the method was declared in, which may be a superinterface of the proxy interface that the proxy class inherits the method through.
    argsObject: an array of objects containing the values of the arguments passed in the method invocation on the proxy instance, or null if interface method takes no arguments. Arguments of primitive types are wrapped in instances of the appropriate primitive wrapper class, such as java.lang.Integer or java.lang.Boolean.
    Returns
    Objectthe value to return from the method invocation on the proxy instance. If the declared return type of the interface method is a primitive type, then the value returned by this method must be an instance of the corresponding primitive wrapper class; otherwise, it must be a type assignable to the declared return type. If the value returned by this method is null and the interface method’s return type is primitive, then a NullPointerException will be thrown by the method invocation on the proxy instance. If the value returned by this method is otherwise not compatible with the interface method’s declared return type as described above, a ClassCastException will be thrown by the method invocation on the proxy instance.

    上面提到的一点需要特别注意的是,如果 Subject 类中定义的方法返回值为 8 种基本数据类型,那么在 ProxySubject 类中必须要返回相应的基本类型包装类,即 int 对应的返回为 Integer 等等,还需要注意的是如果此时返回 null,则会抛出 NullPointerException,除此之外的其他情况下返回值的对象必须要和 Subject 类中定义方法的返回值一致,要不然会抛出 ClassCastException。

    生成源码分析

      那么通过 Proxy 类的 newProxyInstance 方法动态生成的类是什么样子的呢,我们上面也提到了,JDK 为我们提供了一个方法 ProxyGenerator.generateProxyClass(String proxyName,class[] interfaces) 来产生动态代理类的字节码,这个类位于 sun.misc 包中,是属于特殊的 jar 包,于是问题又来了,android studio 创建的 android 工程是没法找到 ProxyGenerator 这个类的,这个类在 jre 目录下,就算我把这个类相关的 .jar 包拷贝到工程里面并且在 gradle 里面引用它,虽然最后能够找到这个类,但是编译时又会出现很奇葩的问题,所以,没办法喽,android studio 没办法创建普通的 java 工程,只能自己装一个 intellij idea 或者求助相关的同事了。创建好 java 工程之后,使用下面这段代码就可以将生成的类导出到指定路径下面:

    public static void generateClassFile(Class clazz,String proxyName)
    {
        //根据类信息和提供的代理类名称,生成字节码  
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String paths = "D:\\"; // 这里写死路径为 D 盘,可以根据实际需要去修改
        System.out.println(paths);
        FileOutputStream out = null;
    
        try {
            //保留到硬盘中  
            out = new FileOutputStream(paths+proxyName+".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    调用代码的方式为:

    generateClassFile(ProxySubject.class, "ProxySubject");  

    最后就会在 D 盘(如果没有修改路径)的根目录下面生成一个 ProxySubject.class 的文件,使用 jd-gui 就可以打开该文件:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class ProxySubject
      extends Proxy
      implements Subject
    {
      private static Method m1;
      private static Method m3;
      private static Method m2;
      private static Method m0;
    
      public ProxySubject(InvocationHandler paramInvocationHandler)
      {
        super(paramInvocationHandler);
      }
    
      public final boolean equals(Object paramObject)
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      public final String operation()
      {
        try
        {
          return (String)this.h.invoke(this, m3, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      public final String toString()
      {
        try
        {
          return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      public final int hashCode()
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      static
      {
        try
        {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m3 = Class.forName("Subject").getMethod("operation", new Class[0]);
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    }

    可以观察到这个生成的类继承自 java.lang.reflect.Proxy,实现了 Subject 接口,我们在看看生成动态类的代码:

    Subject sub = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
            subject.getClass().getInterfaces(), proxy);

    可见这个动态生成类会实现 subject.getClass().getInterfaces() 中的所有接口,并且还有一点是类中所有的方法都是 final 的,而且该类也是 final ,所以该类不可继承,最后就是所有的方法都会调用到 InvocationHandler 对象 h 的 invoke() 方法,这也就是为什么最后会调用到 ProxySubject 类的 invoke() 方法了,画一下它们的简单类图:
    这里写图片描述
    从这个类图可以很清楚的看明白,动态生成的类 ProxySubject(同名,所以后面加上了 Dynamic)持有了实现 InvocationHandler 接口的 ProxySubject 类的对象 h,然后调用代理对象的 operation 方法时,就会调用到对象 h 的 invoke 方法中,invoke 方法中根据 method 的名字来区分到底是什么方法,然后通过 method.invoke() 方法来调用具体对象的对应方法。

    Android 中利用动态代理实现 ServiceHook

      通过上面对 InvocationHandler 的介绍,我们对这个接口应该有了大体的了解,但是在运行时动态生成的代理类有什么作用呢,其实它的作用就是在调用真正业务之前或者之后插入一些额外的操作:
    这里写图片描述
    所以简而言之,代理类的处理逻辑很简单,就是在调用某个方法前及方法后插入一些额外的业务。而我们在 Android 中的实践例子就是在真正调用系统的某个 Service 之前和之后选择性的做一些自己特殊的处理,这种思想在插件化框架上也是很重要的。那么我们具体怎么去实现 hook 系统的 Service ,在真正调用系统 Service 的时候附加上我们需要的业务呢,这就需要介绍 ServiceManager 这个类了。

    ServiceManager 介绍以及 hook 的步骤

      第一步
      关于 ServiceManager 的详细介绍在我的博客:android IPC通信(下)-AIDL 中已经介绍过了,这里就不赘述了,强烈建议大家去看一下那篇博客,我们这里就着重看一下 ServiceManager 的 getService(String name) 方法:

    public final class ServiceManager {
        private static final String TAG = "ServiceManager";
    
        private static IServiceManager sServiceManager;
        private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
    
        private static IServiceManager getIServiceManager() {
            if (sServiceManager != null) {
                return sServiceManager;
            }
    
            // Find the service manager
            sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
            return sServiceManager;
        }
    
        /**
         * Returns a reference to a service with the given name.
         * 
         * @param name the name of the service to get
         * @return a reference to the service, or <code>null</code> if the service doesn't exist
         */
        public static IBinder getService(String name) {
            try {
                IBinder service = sCache.get(name);
                if (service != null) {
                    return service;
                } else {
                    return getIServiceManager().getService(name);
                }
            } catch (RemoteException e) {
                Log.e(TAG, "error in getService", e);
            }
            return null;
        }
    
        public static void addService(String name, IBinder service) {
        ...
        }
        ....
    }

    我们可以看到,getService 方法第一步会去 sCache 这个 map 中根据 Service 的名字获取这个 Service 的 IBinder 对象,如果获取到为空,则会通过 ServiceManagerNative 通过跨进程通信获取这个 Service 的 IBinder 对象,所以我们就以 sCache 这个 map 为切入点,反射该对象,然后修改该对象,由于系统的 android.os.ServiceManager 类是 @hide 的,所以只能使用反射,根据这个初步思路,写下第一步的代码:

    Class c_ServiceManager = Class.forName("android.os.ServiceManager");
    if (c_ServiceManager == null) {
        return;
    }
    
    if (sCacheService == null) {
        try {
            Field sCache = c_ServiceManager.getDeclaredField("sCache");
            sCache.setAccessible(true);
            sCacheService = (Map<String, IBinder>) sCache.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    sCacheService.remove(serviceName);
    sCacheService.put(serviceName, service);

    反射 sCache 这个变量,移除系统 Service,然后将我们自己改造过的 Service put 进去,这样就能实现当调用 ServiceManager 的 getService(String name) 方法的时候,返回的是我们改造过的 Service 而不是系统的原生 Service。
      第二步
      第一步知道了如何去将改造过后的 Service put 进系统的 ServiceManager 中,第二步就是去生成一个 hook Service 了,怎么去生成呢?这就要用到我们上面介绍到的 InvocationHandler 类,我们先获取原生的 Service ,然后通过 InvocationHandler 去构造一个 hook Service,最后通过第一步的步骤 put 进 sCache 这个变量即可,第二步代码:

    public class ServiceHook implements InvocationHandler {
        private static final String TAG = "ServiceHook";
    
        private IBinder mBase;
        private Class<?> mStub;
        private Class<?> mInterface;
        private InvocationHandler mInvocationHandler;
    
        public ServiceHook(IBinder mBase, String iInterfaceName, boolean isStub, InvocationHandler InvocationHandler) {
            this.mBase = mBase;
            this.mInvocationHandler = InvocationHandler;
    
            try {
                this.mInterface = Class.forName(iInterfaceName);
                this.mStub = Class.forName(String.format("%s%s", iInterfaceName, isStub ? "$Stub" : ""));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if ("queryLocalInterface".equals(method.getName())) {
                return Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] { mInterface },
                        new HookHandler(mBase, mStub, mInvocationHandler));
            }
    
            Log.e(TAG, "ERROR!!!!! method:name = " + method.getName());
            return method.invoke(mBase, args);
        }
    
        private static class HookHandler implements InvocationHandler {
            private Object mBase;
            private InvocationHandler mInvocationHandler;
    
            public HookHandler(IBinder base, Class<?> stubClass,
                               InvocationHandler InvocationHandler) {
                mInvocationHandler = InvocationHandler;
    
                try {
                    Method asInterface = stubClass.getDeclaredMethod("asInterface", IBinder.class);
                    this.mBase = asInterface.invoke(null, base);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (mInvocationHandler != null) {
                    return mInvocationHandler.invoke(mBase, method, args);
                }
                return method.invoke(mBase, args);
            }
        }
    }

    这里我们以 ClipboardService 的调用代码为例:

    IBinder clipboardService = ServiceManager.getService(Context.CLIPBOARD_SERVICE);
    String IClipboard = "android.content.IClipboard";
    
    if (clipboardService != null) {
        IBinder hookClipboardService =
                (IBinder) Proxy.newProxyInstance(clipboardService.getClass().getClassLoader(),
                                clipboardService.getClass().getInterfaces(),
                        new ServiceHook(clipboardService, IClipboard, true, new ClipboardHookHandler()));
        //调用第一步的方法
        ServiceManager.setService(Context.CLIPBOARD_SERVICE, hookClipboardService);
    } else {
        Log.e(TAG, "ClipboardService hook failed!");
    }

    分析一下上面的这段代码,分析之前,先要看一下 ClipboardService 的相关类图:

    这里写图片描述
    从这张类图我们可以清晰的看见 ClipboardService 的相关继承关系,接下来就是分析代码了:

    • 调用代码中,Proxy.newProxyInstance 函数的第二个参数需要注意,由于 ClipboardService 继承自三个接口,所以这里需要把所有的接口传递进去,但是如果将第二个参数变更为 new Class[] { IBinder.class } 其实也是没有问题的(感兴趣的可以试一下,第一个参数修改为 IBinder.class.getClassLoader(),第二个参数修改为 new Class[]{IBinder.class},也是可以的),因为实际使用的时候,我们只是用到了 IBinder 类的 queryLocalInterface 方法,其他的方法都没有使用到,接下来我们就会说明 queryLocalInterface 这个函数的作用;
    • Proxy.newProxyInstance 函数的第三个参数为 ServcieHook 对象,所以当把这个 Service set 进 sCache 变量的时候,所有调用 ClipboardService 的操作都将调用到 ServiceHook 中的 invoke 方法中;
    • 接着我们来看看 ServiceHook 的 invoke 函数,很简单,当函数为 queryLocalInterface 方法的时候返回一个 HookHandler 的对象,其他的情况直接调用 method.invoke 原生系统的 ClipboardService 功能,为什么只处理 queryLocalInterface 方法呢,这个我在博客:java/android 设计模式学习笔记(9)—代理模式 中分析 AMS 的时候已经提到了,asInterface 方法最终会调用到 queryLocalInterface 方法,queryLocalInterface 方法最后的返回结果会作为 asInterface 的结果而返回给 Service 的调用方,所以 queryLocalInterface 方法的最后返回的对象是会被外部直接调用的,这也解释了为什么调用代码中的第二个参数变更为 new Class[] { IBinder.class } 也是没有问题,因为第一次调用到 queryLocalInterface 函数之后,后续的所有调用都到了 HookHandler 对象中,动态生成的对象中只需要有 IBinder 的 queryLocalInterface 方法即可,而不需要 IClipboard 接口的其他方法;
    • 接下来是 HookHandler 类,首先我们看看这个类的构造函数,第一个参数为系统的 ClipboardService,第二个参数为

    Class.forName(String.format("%s%s", iInterfaceName, isStub ? "$Stub" : ""))//"android.content.IClipboard"

    这个参数咱们对照上面的类图,这个类为 ClipboardService 的父类,它里面有一个 asInterface 的方法,通过反射 asInterface 方法然后将 IBinder 对象变成 IInterface 对象,为什么要这么做,可以去看看我的博客: java/android 设计模式学习笔记(9)—代理模式 中的最后总结,通过 ServiceManager.getService 方法获取一个 IBinder 对象,但是这个 IBinder 对象不能直接调用,必须要通过 asInterface 方法转成对应的 IInterface 对象才可以使用,所以 mBase 对象其实是一个 IInterface 对象:
    这里写图片描述
    最后也证实了这个结果,为什么是 Proxy 对象这就不用我解释了吧;

    • 最后是 HookHandler 的 invoke 方法,这个方法调用到了 ClipboardHookHandler 对象,我们来看看这个类的实现:
    • public class ClipboardHook {
      
          private static final String TAG = ClipboardHook.class.getSimpleName();
      
          public static void hookService(Context context) {
              IBinder clipboardService = ServiceManager.getService(Context.CLIPBOARD_SERVICE);
              String IClipboard = "android.content.IClipboard";
      
              if (clipboardService != null) {
                  IBinder hookClipboardService =
                          (IBinder) Proxy.newProxyInstance(IBinder.class.getClassLoader(),
                                  new Class[]{IBinder.class},
                                  new ServiceHook(clipboardService, IClipboard, true, new ClipboardHookHandler()));
                  ServiceManager.setService(Context.CLIPBOARD_SERVICE, hookClipboardService);
              } else {
                  Log.e(TAG, "ClipboardService hook failed!");
              }
          }
      
          public static class ClipboardHookHandler implements InvocationHandler {
      
              @Override
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  String methodName = method.getName();
                  int argsLength = args.length;
                  //每次从本应用复制的文本,后面都加上分享的出处
                  if ("setPrimaryClip".equals(methodName)) {
                      if (argsLength >= 2 && args[0] instanceof ClipData) {
                          ClipData data = (ClipData) args[0];
                          String text = data.getItemAt(0).getText().toString();
                          text += "this is shared from ServiceHook-----by Shawn_Dut";
                          args[0] = ClipData.newPlainText(data.getDescription().getLabel(), text);
                      }
                  }
                  return method.invoke(proxy, args);
              }
          }
      }
      所以 ClipboardHookHandler 类的 invoke 方法最终获取到了要 hook 的 Service 的 IInterface 对象(即为 IClipboard.Proxy 对象,最后通过 Binder Driver 调用到了系统的 ClipboardService 中),调用函数的 Method 对象和参数列表对象,获取到了这些之后,不用我说了,就可以尽情的去做一些额外的操作了,我这里是在仿照知乎复制文字时,在后面加上类似的版权声明。

      问题讨论

        上面就是 ServiceHook 的详细步骤了,了解它必须要对 InvocationHandler 有详细的了解,并且还要去看一下 AOSP 源码,比如要去 hook ClipboardService ,那么就要去先看看 ClipboardService 的源码,看看这个类中每个函数的名字和作用,参数列表中每个参数的顺序和作用,而且有时候这还远远不够,我们知道,随着 Android 每个版本的更新,这些类可能也会被更新修改甚至删除,很有可能对于新版本来说老的 hook 方法就不管用了,这时候必须要去了解最新的源码,看看更新修改的地方,针对新版本去重新制定 hook 的步骤,这是一点需要慎重对待考虑的地方。

      步骤

      这里写图片描述

      源码

        此为我们公司某位大神代码,经过整理修改而出,不知道有没有版权问题,哈哈哈,谢谢周杰大神,虽然已经不在公司,感谢感谢~~
        源码下载地址:https://github.com/zhaozepeng/ServiceHook
        先来看看运行的效果:
        这里写图片描述
        最后把所有的代码贴出来:

      ServiceManager.java

      public class ServiceManager {
      
          private static Method sGetServiceMethod;
          private static Map<String, IBinder> sCacheService;
          private static Class c_ServiceManager;
      
          static {
              try {
                  c_ServiceManager = Class.forName("android.os.ServiceManager");
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          public static IBinder getService(String serviceName) {
              if (c_ServiceManager == null) {
                  return null;
              }
      
              if (sGetServiceMethod == null) {
                  try {
                      sGetServiceMethod = c_ServiceManager.getDeclaredMethod("getService", String.class);
                      sGetServiceMethod.setAccessible(true);
                  } catch (NoSuchMethodException e) {
                      e.printStackTrace();
                  }
              }
      
              if (sGetServiceMethod != null) {
                  try {
                      return (IBinder) sGetServiceMethod.invoke(null, serviceName);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
      
              return null;
          }
      
          public static void setService(String serviceName, IBinder service) {
              if (c_ServiceManager == null) {
                  return;
              }
      
              if (sCacheService == null) {
                  try {
                      Field sCache = c_ServiceManager.getDeclaredField("sCache");
                      sCache.setAccessible(true);
                      sCacheService = (Map<String, IBinder>) sCache.get(null);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
              sCacheService.remove(serviceName);
              sCacheService.put(serviceName, service);
          }
      }

      ServiceManager 这个类就是使用反射的方式去获取对应 Service (这里不能使用 Context.getSystemService 函数,因为它的返回不是 IBinder 对象,比如对于 ClipboardService,它就是 ClipboardManager 对象)和设置 service 到 sCache 变量中;

      ServiceHook.java

      public class ServiceHook implements InvocationHandler {
          private static final String TAG = "ServiceHook";
      
          private IBinder mBase;
          private Class<?> mStub;
          private Class<?> mInterface;
          private InvocationHandler mInvocationHandler;
      
          public ServiceHook(IBinder mBase, String iInterfaceName, boolean isStub, InvocationHandler InvocationHandler) {
              this.mBase = mBase;
              this.mInvocationHandler = InvocationHandler;
      
              try {
                  this.mInterface = Class.forName(iInterfaceName);
                  this.mStub = Class.forName(String.format("%s%s", iInterfaceName, isStub ? "$Stub" : ""));
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              }
          }
      
          @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              if ("queryLocalInterface".equals(method.getName())) {
                  return Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] { mInterface },
                          new HookHandler(mBase, mStub, mInvocationHandler));
              }
      
              Log.e(TAG, "ERROR!!!!! method:name = " + method.getName());
              return method.invoke(mBase, args);
          }
      
          private static class HookHandler implements InvocationHandler {
              private Object mBase;
              private InvocationHandler mInvocationHandler;
      
              public HookHandler(IBinder base, Class<?> stubClass,
                                 InvocationHandler InvocationHandler) {
                  mInvocationHandler = InvocationHandler;
      
                  try {
                      Method asInterface = stubClass.getDeclaredMethod("asInterface", IBinder.class);
                      this.mBase = asInterface.invoke(null, base);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
      
              @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  if (mInvocationHandler != null) {
                      return mInvocationHandler.invoke(mBase, method, args);
                  }
                  return method.invoke(mBase, args);
              }
          }
      }

      这个类上面介绍的很详细了,在这里就不继续介绍了;

      ClipboardHook.java

      public class ClipboardHook {
      
          private static final String TAG = ClipboardHook.class.getSimpleName();
      
          public static void hookService(Context context) {
              IBinder clipboardService = ServiceManager.getService(Context.CLIPBOARD_SERVICE);
              String IClipboard = "android.content.IClipboard";
      
              if (clipboardService != null) {
                  IBinder hookClipboardService =
                          (IBinder) Proxy.newProxyInstance(IBinder.class.getClassLoader(),
                                  new Class[]{IBinder.class},
                                  new ServiceHook(clipboardService, IClipboard, true, new ClipboardHookHandler()));
                  ServiceManager.setService(Context.CLIPBOARD_SERVICE, hookClipboardService);
              } else {
                  Log.e(TAG, "ClipboardService hook failed!");
              }
          }
      
          public static class ClipboardHookHandler implements InvocationHandler {
      
              @Override
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  String methodName = method.getName();
                  int argsLength = args.length;
                  //每次从本应用复制的文本,后面都加上分享的出处
                  if ("setPrimaryClip".equals(methodName)) {
                      if (argsLength >= 2 && args[0] instanceof ClipData) {
                          ClipData data = (ClipData) args[0];
                          String text = data.getItemAt(0).getText().toString();
                          text += "this is shared from ServiceHook-----by Shawn_Dut";
                          args[0] = ClipData.newPlainText(data.getDescription().getLabel(), text);
                      }
                  }
                  return method.invoke(proxy, args);
              }
          }
      }

      这里的 hook ClipboardService 使用的是,将复制的文本取出,在结尾处添加我们自定义的文本,用户再粘贴到其他地方的时候,就会出现我们添加上我们自定义文本后的文字了,还有需要注意的是这只会影响应用进程的 ClipboardService,并不会影响主进程的相关 Service,因为不管怎么 hook,修改的都是应用进程的 ServiceManager 里面的 sCache 变量,应用进程的 ServiceManager 其实也就相当于一个 Binder Client,sCache 里面获取不到对应的 Service,它就会自动通过 Binder Driver 和 Binder Server (主进程的 ServiceManager)通信去获取对应的 Service,所以修改 Binder Client,其实是不会影响 Binder Server的,不明白的建议还是看看:android IPC通信(下)-AIDL

      测试代码

      switch (v.getId()) {
          case R.id.btn_copy:
              String input = mEtInput.getText().toString().trim();
              if (TextUtils.isEmpty(input)) {
                  Toast.makeText(this, "input不能为空", Toast.LENGTH_SHORT).show();
                  return;
               }
      
              //复制
              ClipData clip = ClipData.newPlainText("simple text", mEtInput.getText().toString());
              clipboard.setPrimaryClip(clip);
              break;
          case R.id.btn_show_paste:
              //黏贴
              clip = clipboard.getPrimaryClip();
              if (clip != null && clip.getItemCount() > 0) {
                  Toast.makeText(this, clip.getItemAt(0).getText(), Toast.LENGTH_SHORT).show();
              }
              break;
      }

      测试代码,我这里就不需要说明了,Clipboard 的简单使用而已。  
        这里只演示了 hook ClipboardService 的例子,其他的使用方式比如插件化等等在这里就不一一介绍了,感兴趣的可以去网上查阅相关的资料。
        转载请注明出处:http://blog.csdn.net/self_study/article/details/55050627

      引用

      http://blog.csdn.net/luanlouis/article/details/24589193
      http://www.cnblogs.com/xiaoluo501395377/p/3383130.html
      http://blog.csdn.net/self_study/article/details/51628486
      http://paddy-w.iteye.com/blog/841798
      http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

    展开全文
  • 【Spring基础】CGLIB动态代理实现原理

    万次阅读 多人点赞 2018-06-09 18:11:19
    前言 ... 一 CGLIB介绍 CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库, 它可以在运行期扩展Java类与实现...Hibernate用它来实现PO(Persistent Object 持久化对象)...

    前言

    Github:https://github.com/yihonglei/thinking-in-spring(spring工程)

    一 CGLIB介绍

    CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,

    它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

    CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供

    方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

    除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,

    因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

    二 CGLIB动态代理实例

    实现一个业务类,注意,这个业务类并没有实现任何接口:

    package com.jpeony.spring.proxy.cglib;
    
    public class HelloService {
    
        public HelloService() {
            System.out.println("HelloService构造");
        }
    
        /**
         * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
         */
        final public String sayOthers(String name) {
            System.out.println("HelloService:sayOthers>>"+name);
            return null;
        }
    
        public void sayHello() {
            System.out.println("HelloService:sayHello");
        }
    }
    

    自定义MethodInterceptor:

    package com.jpeony.spring.proxy.cglib;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * 自定义MethodInterceptor
     */
    public class MyMethodInterceptor implements MethodInterceptor{
    
        /**
         * sub:cglib生成的代理对象
         * method:被代理对象方法
         * objects:方法入参
         * methodProxy: 代理方法
         */
        @Override
        public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("======插入前置通知======");
            Object object = methodProxy.invokeSuper(sub, objects);
            System.out.println("======插入后者通知======");
            return object;
        }
    }

    生成CGLIB代理对象调用目标方法:

    package com.jpeony.spring.proxy.cglib;
    
    import net.sf.cglib.core.DebuggingClassWriter;
    import net.sf.cglib.proxy.Enhancer;
    
    public class Client {
        public static void main(String[] args) {
            // 代理类class文件存入本地磁盘方便我们反编译查看源码
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
            // 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            // 设置enhancer对象的父类
            enhancer.setSuperclass(HelloService.class);
            // 设置enhancer的回调对象
            enhancer.setCallback(new MyMethodInterceptor());
            // 创建代理对象
            HelloService proxy= (HelloService)enhancer.create();
            // 通过代理对象调用目标方法
            proxy.sayHello();
        }
    }

    运行结果:

    三 CGLIB动态代理源码分析

    实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:

    /*
     * Copyright 2002,2003 The Apache Software Foundation
     *
     *  Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package net.sf.cglib.proxy;
    
    /**
     * General-purpose {@link Enhancer} callback which provides for "around advice".
     * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
     * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
     */
    public interface MethodInterceptor
    extends Callback
    {
        /**
         * All generated proxied methods call this method instead of the original method.
         * The original method may either be invoked by normal reflection using the Method object,
         * or by using the MethodProxy (faster).
         * @param obj "this", the enhanced object
         * @param method intercepted Method
         * @param args argument array; primitive types are wrapped
         * @param proxy used to invoke super (non-intercepted method); may be called
         * as many times as needed
         * @throws Throwable any exception may be thrown; if so, super method will not be invoked
         * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
         * @see MethodProxy
         */    
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
    
    }
    

    这个接口只有一个intercept()方法,这个方法有4个参数:

    1)obj表示增强的对象,即实现这个接口类的一个对象;

    2)method表示要被拦截的方法;

    3)args表示要被拦截方法的参数;

    4)proxy表示要触发父类的方法对象;

    在上面的Client代码中,通过Enhancer.create()方法创建代理对象,create()方法的源码:

    /**
         * Generate a new class if necessary and uses the specified
         * callbacks (if any) to create a new object instance.
         * Uses the no-arg constructor of the superclass.
         * @return a new instance
         */
        public Object create() {
            classOnly = false;
            argumentTypes = null;
            return createHelper();
        }

    该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,

    使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,源码如下:

    private Object createHelper() {
            preValidate();
            Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                    ReflectUtils.getNames(interfaces),
                    filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                    callbackTypes,
                    useFactory,
                    interceptDuringConstruction,
                    serialVersionUID);
            this.currentKey = key;
            Object result = super.create(key);
            return result;
        }

    preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。

    通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法

    创建代理对象的参数。

    protected Object create(Object key) {
            try {
                ClassLoader loader = getClassLoader();
                Map<ClassLoader, ClassLoaderData> cache = CACHE;
                ClassLoaderData data = cache.get(loader);
                if (data == null) {
                    synchronized (AbstractClassGenerator.class) {
                        cache = CACHE;
                        data = cache.get(loader);
                        if (data == null) {
                            Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                            data = new ClassLoaderData(loader);
                            newCache.put(loader, data);
                            CACHE = newCache;
                        }
                    }
                }
                this.key = key;
                Object obj = data.get(this, getUseCache());
                if (obj instanceof Class) {
                    return firstInstance((Class) obj);
                }
                return nextInstance(obj);
            } catch (RuntimeException e) {
                throw e;
            } catch (Error e) {
                throw e;
            } catch (Exception e) {
                throw new CodeGenerationException(e);
            }
        }

    真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:

    abstract protected Object nextInstance(Object instance) throws Exception;

    在子类Enhancer中实现,实现源码如下:

    protected Object nextInstance(Object instance) {
            EnhancerFactoryData data = (EnhancerFactoryData) instance;
    
            if (classOnly) {
                return data.generatedClass;
            }
    
            Class[] argumentTypes = this.argumentTypes;
            Object[] arguments = this.arguments;
            if (argumentTypes == null) {
                argumentTypes = Constants.EMPTY_CLASS_ARRAY;
                arguments = null;
            }
            return data.newInstance(argumentTypes, arguments, callbacks);
        }

    看看data.newInstance(argumentTypes, arguments, callbacks)方法,

    第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。

    最后根据这些参数,通过反射生成代理对象,源码如下:

    /**
             * Creates proxy instance for given argument types, and assigns the callbacks.
             * Ideally, for each proxy class, just one set of argument types should be used,
             * otherwise it would have to spend time on constructor lookup.
             * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
             * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
             *
             * @see #createUsingReflection(Class)
             * @param argumentTypes constructor argument types
             * @param arguments constructor arguments
             * @param callbacks callbacks to set for the new instance
             * @return newly created proxy
             */
            public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
                setThreadCallbacks(callbacks);
                try {
                    // Explicit reference equality is added here just in case Arrays.equals does not have one
                    if (primaryConstructorArgTypes == argumentTypes ||
                            Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
                        // If we have relevant Constructor instance at hand, just call it
                        // This skips "get constructors" machinery
                        return ReflectUtils.newInstance(primaryConstructor, arguments);
                    }
                    // Take a slow path if observing unexpected argument types
                    return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
                } finally {
                    // clear thread callbacks to allow them to be gc'd
                    setThreadCallbacks(null);
                }
    
            }

    最后生成代理对象:

    将其反编译后代码如下:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.jpeony.spring.proxy.cglib;
    
    import java.lang.reflect.Method;
    import net.sf.cglib.core.ReflectUtils;
    import net.sf.cglib.core.Signature;
    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.Factory;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class HelloService$$EnhancerByCGLIB$$be45efdd extends HelloService implements Factory {
        private boolean CGLIB$BOUND;
        public static Object CGLIB$FACTORY_DATA;
        private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
        private static final Callback[] CGLIB$STATIC_CALLBACKS;
        private MethodInterceptor CGLIB$CALLBACK_0;
        private static Object CGLIB$CALLBACK_FILTER;
        private static final Method CGLIB$sayHello$0$Method;
        private static final MethodProxy CGLIB$sayHello$0$Proxy;
        private static final Object[] CGLIB$emptyArgs;
        private static final Method CGLIB$equals$1$Method;
        private static final MethodProxy CGLIB$equals$1$Proxy;
        private static final Method CGLIB$toString$2$Method;
        private static final MethodProxy CGLIB$toString$2$Proxy;
        private static final Method CGLIB$hashCode$3$Method;
        private static final MethodProxy CGLIB$hashCode$3$Proxy;
        private static final Method CGLIB$clone$4$Method;
        private static final MethodProxy CGLIB$clone$4$Proxy;
    
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$be45efdd");
            Class var1;
            Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
            CGLIB$equals$1$Method = var10000[0];
            CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
            CGLIB$toString$2$Method = var10000[1];
            CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
            CGLIB$hashCode$3$Method = var10000[2];
            CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
            CGLIB$clone$4$Method = var10000[3];
            CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
            CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService")).getDeclaredMethods())[0];
            CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
        }
    
        final void CGLIB$sayHello$0() {
            super.sayHello();
        }
    
        public final void sayHello() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
            } else {
                super.sayHello();
            }
        }
    
        final boolean CGLIB$equals$1(Object var1) {
            return super.equals(var1);
        }
    
        public final boolean equals(Object var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
                return var2 == null ? false : (Boolean)var2;
            } else {
                return super.equals(var1);
            }
        }
    
        final String CGLIB$toString$2() {
            return super.toString();
        }
    
        public final String toString() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
        }
    
        final int CGLIB$hashCode$3() {
            return super.hashCode();
        }
    
        public final int hashCode() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
                return var1 == null ? 0 : ((Number)var1).intValue();
            } else {
                return super.hashCode();
            }
        }
    
        final Object CGLIB$clone$4() throws CloneNotSupportedException {
            return super.clone();
        }
    
        protected final Object clone() throws CloneNotSupportedException {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
            String var10000 = var0.toString();
            switch(var10000.hashCode()) {
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$4$Proxy;
                }
                break;
            case 1535311470:
                if (var10000.equals("sayHello()V")) {
                    return CGLIB$sayHello$0$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$1$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$2$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$3$Proxy;
                }
            }
    
            return null;
        }
    
        public HelloService$$EnhancerByCGLIB$$be45efdd() {
            CGLIB$BIND_CALLBACKS(this);
        }
    
        public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
            CGLIB$THREAD_CALLBACKS.set(var0);
        }
    
        public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
            CGLIB$STATIC_CALLBACKS = var0;
        }
    
        private static final void CGLIB$BIND_CALLBACKS(Object var0) {
            HelloService$$EnhancerByCGLIB$$be45efdd var1 = (HelloService$$EnhancerByCGLIB$$be45efdd)var0;
            if (!var1.CGLIB$BOUND) {
                var1.CGLIB$BOUND = true;
                Object var10000 = CGLIB$THREAD_CALLBACKS.get();
                if (var10000 == null) {
                    var10000 = CGLIB$STATIC_CALLBACKS;
                    if (var10000 == null) {
                        return;
                    }
                }
    
                var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
            }
    
        }
    
        public Object newInstance(Callback[] var1) {
            CGLIB$SET_THREAD_CALLBACKS(var1);
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Callback var1) {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
            CGLIB$SET_THREAD_CALLBACKS(var3);
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd;
            switch(var1.length) {
            case 0:
                var10000.<init>();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    
        public Callback getCallback(int var1) {
            CGLIB$BIND_CALLBACKS(this);
            MethodInterceptor var10000;
            switch(var1) {
            case 0:
                var10000 = this.CGLIB$CALLBACK_0;
                break;
            default:
                var10000 = null;
            }
    
            return var10000;
        }
    
        public void setCallback(int var1, Callback var2) {
            switch(var1) {
            case 0:
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            default:
            }
        }
    
        public Callback[] getCallbacks() {
            CGLIB$BIND_CALLBACKS(this);
            return new Callback[]{this.CGLIB$CALLBACK_0};
        }
    
        public void setCallbacks(Callback[] var1) {
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        }
    
        static {
            CGLIB$STATICHOOK1();
        }
    }
    

    重点关注代理对象的sayHello方法:

    从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,

    intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中

    的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

    JDK动态代理实现原理(jdk8)

     

    展开全文
  • ButterKnife的实现需要先熟悉注解、反射、动态代理,不熟悉的小伙伴可以去看这三篇文章: Java注解 Java反射 动态代理 下面我们就来看一下ButterKnife的实现: ButterKnife相信大家都会用,它能通过注解帮我们...
  • java动态代理实现接口调用

    千次阅读 2019-10-14 11:17:33
    动态代理是基于接口实现的代理,mybatis就是用这个技术实现的 首先,创建一个最基本接口和实现类: interface UserManager { void addUser(); } class UserManagerImpl implements UserManager{ @Override ...
  • java动态代理实现

    千次阅读 多人点赞 2019-01-15 14:42:46
    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。  一、代理模式  代理模式是常用的java设计模式,他的特征是...
  • 动态代理实现原理

    千次阅读 2022-04-14 15:40:13
    首先,动态代理是代理模式的一种实现方式,代理模式除了动态代理还有静态代理,只不过静态代理能够在编译时期确定类的执行对象,而动态代理只有在运行时才能够确定执行对象是谁。代理可以看作是对最终调用目标的一个...
  • 今天来讲一下mybatis的实现原理,我们都知道mybatis是使用动态代理的方式实现的一套ORM框架,那么他是怎么实现的呢? 在回答这个问题之前,我们先来捋一下mybatis框架的使用流程,一般我们会把他跟spring一起结合...
  • 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能...下面我们讲讲jdk动态代理和cglib动态代理实现及区别 jdk动态代理...
  • SpringJDK动态代理实现

    千次阅读 2021-01-17 22:18:01
    目录JDK动态代理代码实现 JDK动态代理 JDK动态代理使用Proxy类里面的newProxyInstance方法创建代理对象。 Modifier and Type Method and Description static Object newProxyInstance(ClassLoader loader, ...
  • 我们知道MyBatis通过动态代理的方式,实现了只通过Mapper接口而无接口的实现类的方式操作数据库。 熟悉源码的同学应该知道如下代码(MapperProxy.invoke()): ``` @Override public Object invoke...
  • java动态代理实现步骤解析

    千次阅读 2017-01-04 20:39:04
    RealSubject:真实主题角色,是实现抽象主题接口的类。 Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,...
  • JDK和CGLib动态代理实现和区别

    千次阅读 2019-12-02 16:38:25
    JDK和CGLib动态代理实现 动态代理在Java中有着广泛的应用,如Spring AOP,Hibernate数据查询、测试框架的后端mock、RPC,Java注解对象获取等。动态代理的代理关系是在运行时期确定的。在讲解两种动态代理区别之前,...
  • Java中使用动态代理实现拦截器

    千次阅读 2017-05-17 09:36:55
    拦截器在在流行的开源框架中很常见,依赖的技术就是Java的动态代理。 理解拦截器的核心原理对理解这些开源框架的体系结构至关重要。 下面以一个简单的模型的来说明拦截器的实现的一般方法。   模型分为...
  • JDK动态代理实现原理----JDK1.8

    千次阅读 多人点赞 2018-09-06 14:20:11
    1.代理模式 Proxy里面有个RealSubject对象,初始化的时候将RealSubject对象传入,进行Proxy中RealSubject的对象进行初始化,然后Proxy中的方法,都是调用Proxy对象的方法,可在前后加需求,客户端只需使用多态,...
  • 动态代理是 AOP(Aspect Orient Programming)编程思想,理解动态代理原理,对学习AOP框架至关重要。 JDK动态代理不需要任何外部依赖,但是只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有...
  • cglib动态代理实现原理详细分析

    千次阅读 2019-01-01 18:29:08
    在上篇JDK动态代理实现原理详细分析中,对其JDK代理的流程做了一个详细的分析。而本文,将介绍另一种动态代理模式:cglib动态代理。阅读完本文,你将对cglib代理模式的运行的流程有一个清晰的认识。 本文的目录如下:...
  • Java JDK 动态代理实现和代码分析

    千次阅读 2021-06-02 20:51:44
    JDK 动态代理实现步骤5. JDK 动态代理 API5.1 java.lang.reflect.Proxy5.1 java.lang.reflect.InvocationHandler二、JDK 动态代理的实现(代码)1. 项目结构图2. IRentService 接口3. LandlordServiceImpl 真实类4....
  • 用JAVA动态代理实现RPC框架

    千次阅读 2016-08-17 17:15:25
    动态代理其实就是Java.lang.reflect.Proxy类动态的根据指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有指定的接口(在参数中传入的接口数组),也就 是说,返回的对象可以转换类型为接口数组中...
  • 动态代理实现日志的写入

    千次阅读 2015-03-31 16:39:29
    之前在学习设计模式的时候就学习过代理模式,在DRP的学习过程中,又一次遇到了代理模式,但是这次接触到的是动态代理。做项目的时候也听同学们提到过AOP,那么动态代理和AOP是一种什么样的关系呢?    一、代理...
  • 动态代理实现AOP

    千次阅读 热门讨论 2017-10-14 21:32:29
    今天说和小张哥一起讨论AOP,正好看到了相关的视频,今天就总结一下AOP是如何使用动态代理实现的。AOP对JAVA程序员来说并不陌生,他是spring的一个核心内容——面向切面编程,先把概念放在这里,因为这一篇博客...
  • 【Spring基础】JDK动态代理实现原理(jdk8)

    万次阅读 多人点赞 2018-06-05 21:32:47
    前言 Github:... 一 JDK动态代理 在了解JDK动态代理前,有需要可以了解下代理模式。 ...天天的都听到人们说JDK动态代理,听上去感觉好屌的样子,为什么要叫JDK动态代理? ...
  • 上篇介绍了一下静态代理:Java中的代理模式——静态代理以及分析静态代理的缺点 也分析了一下静态代理的缺点: 1、由于静态代理中的代理类是针对某一个类去做代理的,那么假设一个系统中有100个Service,则需要...
  • 模拟JDK动态代理实现

    千次阅读 2016-06-01 19:46:37
    在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理实现AOP的绝好底层技术。 JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个...
  • 摘要:本文主要讲了Spring Aop动态代理实现的两种方式。 1. Spring AOP Spring是一个轻型容器,Spring整个系列的最最核心的概念当属IoC、AOP。可见AOP是Spring框架中的核心之一,在应用中具有非常重要的作用,也是...
  • Java JDK 动态代理(AOP)使用及实现原理分析

    万次阅读 多人点赞 2019-05-08 21:28:06
    四、动态代理怎么实现的? 五、结论 一、什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息...
  • Java 中,实现动态代理有两种方式: 1、JDK 动态代理:java.lang.reflect 包中的 Proxy 类和 InvocationHandler 接口提供了生成动态代理类的能力。 2、Cglib 动态代理:Cglib (Code Generation Library )是一个第三...
  • go利用monkey框架的动态代理实现AOP

    千次阅读 2019-09-30 16:04:32
    从java转go以来一直在寻找动态代理实现方案,几经波折,终于找到了位牛人写的框架monkey,简单喵了下其源码,貌似是通过替换底层函数字节码来达到动态替换效果,后续再仔细拜读。这里我利用monkey框架实现了一个...
  • java动态代理实现与原理详细分析

    千次阅读 多人点赞 2019-02-08 23:22:43
    一、代理 (1)、什么是代理? 大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户----&gt;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 402,462
精华内容 160,984
关键字:

动态代理怎么实现