2021-05-03 09:52  阅读(141)
文章分类:Spring 入门教程 文章标签:SpringSpring 教程
©  原文作者:一点教程 原文地址:http://www.yiidian.com/spring/

需求:CustomerService业务类,有save,update方法,希望在save,update方法执行之前记录日志。

接下来使用JDK动态代理实现:

一、编写业务类

CustomerService接口:

    
    package com.yiidian.service;
    /**
     * @author http://www.yiidian.com
     *
     */
    public interface CustomerService {
    
    	public void save();
    	
    	public void update();
    }
    

CustomerServiceImpl实现:

    
    package com.yiidian.service.impl;
    
    import com.yiidian.service.CustomerService;
    /**
     * 这个类在AOP属于目标对象(Target)
     * @author http://www.yiidian.com
     *
     */
    public class CustomerServiceImpl implements CustomerService {
    
    	@Override
    	public void save() {
    		System.out.println("执行save方法");
    	}
    
    	@Override
    	public void update() {
    		System.out.println("执行update方法");
    	}
    
    }
    

二、编写JDK动态代理工具类

该工具类,专门用于生成某个接口实现类(目标对象)的代理对象。

    
    package com.yiidian.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    /**
     * @author http://www.yiidian.com
     *
     */
    public class JDKProxyUtils {
    
    	/**
    	 * 使用JDK动态代理获取代理对象
    	 * target: 目标对象
    	 * @return
    	 */
    	public static Object getProxy(final Object target){
    		return Proxy.newProxyInstance(
    				target.getClass().getClassLoader(),    // 和目标对象一样的类加载器
    				target.getClass().getInterfaces(), // 目标对象的接口列表
    				new InvocationHandler() {
    					
    					//invoke: 这个方法在每次调用代理类对象的时候被执行啦!!!
    					@Override
    					public Object invoke(Object proxy, Method method, Object[] args)
    							throws Throwable {
    						System.out.println("记录日志");
    						
    						//调用目标对象的方法
    						return method.invoke(target, args);
    					}
    				});
    	}
    }
    

三、编写测试类

    
    package com.yiidian.test;
    
    import org.junit.Test;
    
    import com.yiidian.proxy.JDKProxyUtils;
    import com.yiidian.service.CustomerService;
    import com.yiidian.service.impl.CustomerServiceImpl;
    /**
     * @author http://www.yiidian.com
     *
     */
    public class Demo1 {
    	
    	@Test
    	public void test1(){
    		//目标对象
    		CustomerService service = new CustomerServiceImpl();
    		//获取JDK动态代理对象(接口代理)
    		CustomerService proxy = (CustomerService)JDKProxyUtils.getProxy(service);
    		//调用代理对象
    		proxy.save();
    		proxy.update();
    	}
    	
    }
    

四、运行结果

202105030952005951.png

从运行结果看出,CustomerService的save和update方法都成功在执行之前,切入了日志代码。

五、案例分析

上面代码中,Proxy类的静态方法newProxyInstance()方法生成了一个对象,这个对象实现了CustomerService中指定的接口。返回值是CustomerService接口的实现类。

动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可。

newProxyInstance()方法的参数
Proxy类的newInstance()方法有三个参数:
1、ClassLoader loader:它是类加载器类型,CustomerService.class.getClassLoader()就可以获取到ClassLoader对象,只要你有一个Class对象就可以获取到ClassLoader对象;

2、Class[] interfaces:指定newProxyInstance()方法返回的对象要实现哪些接口,没错,可以指定多个接口,例如上面例子只我们只指定了一个接口:Class[] cs = {CustomerService.class};

3、InvocationHandler h:它是最重要的一个参数!它是一个接口!它的名字叫调用处理器!上面例子中proxy代理对象是CustomerService接口的实现类对象,那么它可以调用save()和update()方法,其实无论你调用代理对象的什么方法,它都是在调用InvocationHandler的invoke()方法!

202105030952006612.png

源码下载:http://pan.baidu.com/s/1eSfEEwa

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> AOP底层-JDK动态代理
上一篇
AOP相关术语
下一篇
AOP底层-Cglib子类代理