动态代理的两种实现方式

实现动态代理有两种方式:JDK动态代理和CGLIB动态代理。JDK动态代理需要提供接口,MyBatis的Mapper的实现方式就是,CGLIB不需要提供接口,延迟加载就是其应用。

第一种:JDK动态代理的演示。

  1. 编写服务类和接口,是真正的服务提供者;
  2. 编写代理类,提供绑定和代理方法。

服务接口

public interface HelloSerevice {

	public void sayHello(String name);
}

接口的实现类

public class HelloServiceImpl implements HelloSerevice{

	@Override
	public void sayHello(String name) {
		System.out.println("您好"+name);
	}

}

代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理类,提供真实对象的绑定和代理方法,代理类的要求是实现InvocationHandler接口的代理方法
public class HelloServiceProxy implements InvocationHandler{

	private Object target;
	
	//绑定真实提供服务的对象
	public Object bind(Object target) {
		this.target = target;
		/**
		 * 获得代理对象
		 * 第一个参数:获得类加载器
		 * 第二个参数:代理对象所属的接口
		 * 第三个对象:this表示当前类,提供服务的代理类
		 */
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), this);//jdk代理需要提供接口
	}
	@Override
	/**Object proxy代理对象
	 * Method method提供的方法
	 * Object[] args方法的参数
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = null;
		System.out.println("-----------我是jdk动态代理----------");
		System.out.println("方法调用前...");
		//通过反射调用真正提供服务的对象方法
		result = method.invoke(target, args);
		System.out.println("方法调用后...");
		return result;
	}

}

测试类

//测试类
public class HelloServiceTest {

	public static void main(String[] args) {
		
		HelloServiceProxy hsp = new HelloServiceProxy();
		HelloServices hs = (HelloServices)hsp.bind(new HelloServiceImpl());
		hs.sayHello("后羿");
	}
}

输出:
-----------我是jdk动态代理----------
方法调用前...
您好啊!后羿
方法调用后...

MyBatis在实现Mapper接口就是这么做的。

第二种:CGLIB动态代理

JDK动态代理有一个缺点就是必须提供接口才可以使用,所以有了CGLIB动态代理,是一款流行的动态代理开源框架。
接口和实现类都不需要改变,下面实现CGLIB代理类,注意MethodInterceptor我是在Springboot项目中实现的,Java基础包中没有这个接口。

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 HelloServiceCgLib implements MethodInterceptor{

	private Object target;
	
	public Object getInstance(Object target) {
		this.target = target;
		//作用就是设置代理类和回调方法
		Enhancer enhancer = new Enhancer();
		//设置超类
		enhancer.setSuperclass(this.target.getClass());
		//回调方法
		enhancer.setCallback(this);
		//创建代理对象
		return enhancer.create();
	}
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		Object result = null;
		System.out.println("我是CGLIB动态代理");
		System.out.println("代理方法调用前...");
		result = proxy.invokeSuper(obj, args);
		System.out.println("代理方法调用后...");
		return result;
	}

}

测试类

//测试类
public class HelloServiceCGLibTest {

	public static void main(String[] args) {
		
		HelloServiceCgLib hscl = new HelloServiceCgLib();
		HelloServiceImpl hsl = (HelloServiceImpl)hscl.getInstance(new HelloServiceImpl());
		hsl.sayHello("伽罗");
	}
}
输出:
我是CGLIB动态代理
代理方法调用前...
您好啊!伽罗
代理方法调用后...

通常在MyBatis的延迟加载在会用到CGLIB动态代理。

发布了36 篇原创文章 · 获赞 50 · 访问量 9719

猜你喜欢

转载自blog.csdn.net/qq_41765969/article/details/104209774