aop编程之使用jdk动态代理生成代理对象,实现日志输出功能

动态代理工厂实现有两种

  • 第一种是jdk的动态实现:要求面向接口编程,最后生产的代理对象其实是目标对象的兄弟
  • 第二种是cglib动态实现:不需要面向接口编程,最后生产的代理对象其实是目标对象的儿子
    这些方法有助于我们理解工厂模式。

jdk的动态代理实现

同样是需要面向接口编程,然后目标类事项该接口,在定义代理工厂生产目标对象。

编写接口BookServiceIfac接口,定义借书和还书的方法

package 动态代理_jdk;

public interface BookServiceIfac {
	public void borrowBook(String bookName);
	public void returnBook(String bookName);
}

编写BookServiceImpl目标类,实现BookServiceIfac 接口,必定要实现接口定义的方法,如下:

package 动态代理_jdk;

public class BookServiceImpl implements BookServiceIfac {
	@Override
	public void borrowBook(String bookName) {
		System.out.println("借了"+bookName);
	}
	@Override
	public void returnBook(String bookName) {
		System.out.println("还了"+bookName);
	}
}

编写ServiceProxyFactory工厂类,专门生产BookServiceImpl 这个目标对象,如下;

package 动态代理_jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 专门生产service类的代理对象,所以是ServiceProxyFactory
 */
public class ServiceProxyFactory implements InvocationHandler{
	
	private Logger log=Logger.getLogger("动态代理_jdk.ServiceProxyFactory");
	
	private Object target;
	
	/**
	 * 定义生产代理对象的方法
	 * @return
	 */
	public Object getProxy(Object target)
	{
		this.target=target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
		//target.getClass().getClassLoader()目标对象的类加载器
		//target.getClass().getInterfaces()目标对象实现的接口
		//this  当前接口
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		//由于方法调用前日志输出,所以现在日志输出
		log.log(Level.INFO, "调用"+method.getName()+"之前日志输出。。。");
		log.log(Level.INFO,"传给方法的参数:"+Arrays.toString(args));
		//这行代码就能真正地调用目标对象的方法
		/*
		 * obj是目标对象
		 * args是传给方法的参数
		 */
		method.invoke(target, args);
		return null;
	}
}

编写测试类

package 动态代理_jdk;

public class Test {

	public static void main(String[] args) {
		//需求:调用BookService,发现扩展了日志输出功能
		
		ServiceProxyFactory factory =new ServiceProxyFactory();
		
		BookServiceIfac bookService=new BookServiceImpl();
		
		BookServiceIfac proxyobj=(BookServiceIfac) factory.getProxy(bookService);
		
		proxyobj.borrowBook("呼啸山庄");
	}
}

cglib动态代理

实现cglib需要到两个包,一个是asm和cglib
aop编程之使用jdk动态代理生成代理对象,实现日志输出功能_第1张图片
编写一个UserDao类,在里面输出一句话,方便看到结果,代码如下:

package 动态代理_cglib;

public class UserDao {
	
	public Integer deleteUser(Integer userId)
	{
		System.out.println("deleteUser:"+userId);
		return userId;
	}

}

在编写一个专门输出日志的代理工厂类DaoProxyFactory_logout,这个类需要继承MethodInterceptor接口,需要实现接口的intercept方法,代码如下:

package 动态代理_cglib;

import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class DaoProxyFactory_logout implements MethodInterceptor{
	
	private Logger log=Logger.getLogger("动态代理_cglib.DaoProxyFactory_logout");
	
	private Object target;
	
	public Object getProxy(Object target)
	{
		this.target=target;
		Enhancer hancer=new Enhancer();// 增强器; 
		
		hancer.setSuperclass(target.getClass());//代理对象是目标对象的儿子
		hancer.setCallback(this);//当我们调用代理对象的方法时后台调用的是回调对象的intercept方法
		return hancer.create();//创建代理对象
	}

	@Override
	public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
		// 调用目标对象的方法
		Object o=method.invoke(target, args);
		//调用方法之后日志输出
		//System.out.println();
		log.log(Level.INFO, "调用方法之后日志输出");
		return o;
	}
}

编写测试类,查看结果

package 动态代理_cglib;

public class Test {

	public static void main(String[] args) {
		// 测试,希望调用dao的方法能够日志输出
		DaoProxyFactory_logout factory=new DaoProxyFactory_logout(); //实例化代理工厂
		
		UserDao userDao=new UserDao();
		
		UserDao proxy=(UserDao) factory.getProxy(userDao); //给代理工厂传目标对象UserDaO

		Integer id=proxy.deleteUser(100);
		
		System.out.println(id);
	}
}

运行代码,查看控制台日志输出:

aop编程之使用jdk动态代理生成代理对象,实现日志输出功能_第2张图片

你可能感兴趣的:(spring)