代理在生活中比较常见,比如常见的代理商,对工厂进行代理,工厂专注生产,代理商负责经销,用户购买商品从代理商手中购买。java中代理分为动态代理与静态代理,其中动态代理比较常见的有jdk动态代理和cglib动态代理。
静态代理
静态代理实现简单,但不够灵活,比较麻烦,要实现与被代理对象一样的接口,创建很多代理类。接口增加方法后代理类与被代理对象都要加方法。以日志代理举例:
1.创建订单接口
/**
* 订单接口
*
* @author huaisf
*
*/
public interface OrderService {
/**
* 保存订单
*/
void saveOrder();
/**
* 查询订单
*/
void selectOrder();
}
2.创建实现类
/**
* 订单接口实现
*
* @author huaisf
*
*/
public class OrderServiceImpl implements OrderService {
public void saveOrder() {
System.out.println("保存成功");
}
public void selectOrder() {
System.out.println("查询成功");
}
}
3.创建代理类
/**
* 日志代理
*
* @author huaisf
*
*/
public class LoggerProxy implements OrderService {
private OrderServiceImpl orderServiceImpl;
public LoggerProxy(OrderServiceImpl orderServiceImpl) {
this.orderServiceImpl = orderServiceImpl;
}
/**
* 执行方法前后打印日志,由于接口单继承,现在想给用户服务打印日志要专门写一个用户的loggerProxy,
* 而且OrderService增加方法,代理类也要变动
*/
public void saveOrder() {
System.out.println("执行前打印日志");
orderServiceImpl.saveOrder();
System.out.println("执行后打印日志");
}
public void selectOrder() {
System.out.println("执行前打印日志");
orderServiceImpl.saveOrder();
System.out.println("执行后打印日志");
}
}
4.编写测试类
public class Test {
public static void main(String[] args) {
OrderServiceImpl orderServiceImpl = new OrderServiceImpl();
LoggerProxy loggerProxy = new LoggerProxy(orderServiceImpl);
loggerProxy.saveOrder();
}
}
jdk动态代理
只针对接口代理,相比于静态代理来说不用写大量重复代码,不用实现接口。在进行代理时,其使用反射机制生成一个实现代理接口的匿名类,然后重写该方法,生成的速度快,但基于反射,后续调用慢。还以日志代理举例:
1.创建订单接口
/**
* 订单接口
*
* @author huaisf
*
*/
public interface OrderService {
/**
* 保存订单
*/
void saveOrder();
/**
* 查询订单
*/
void selectOrder();
}
2.创建实现类
/**
* 订单接口实现
*
* @author huaisf
*
*/
public class OrderServiceImpl implements OrderService {
public void saveOrder() {
System.out.println("保存成功");
}
public void selectOrder() {
System.out.println("查询成功");
}
}
3.编写动态代理接口
package com.shaofei.controller;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 日志代理
*
* @author huaisf
*
*/
public class LoggerProxy {
private Object oject;
public LoggerProxy(Object oject) {
this.oject = oject;
}
/**
* 生成代理对象,不用实现接口,代理方法只需写一次,新增被代理类可复用
*
* @return
*/
public Object getProxyInstance() {
return Proxy.newProxyInstance(oject.getClass().getClassLoader(), oject.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前打印日志");
Object returnValue = method.invoke(oject, args);
System.out.println("执行后打印日志");
return returnValue;
}
});
}
}
4.编写测试类
public class Test {
public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
OrderService proxy = (OrderService) new LoggerProxy(orderService).getProxyInstance();
proxy.saveOrder();
}
}
cglib代理
cglib代理也叫子类代理,基于继承机制,通过asm字节码框架转换字节码重写父类方法达到增强作用,所以被代理类不能为final,其方法不能为final或static。其缺点为生成字节码较慢,但生成后调用快。
1.引入cglib依赖,目前最新版本为3.3.0。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2.创建被代理类
/**
* 订单接口
*
* @author huaisf
*
*/
public class OrderServiceImpl {
/**
* 保存订单
*/
public void saveOrder() {
System.out.println("保存成功");
}
/**
* 查询订单
*/
public void selectOrder() {
System.out.println("查询成功");
}
}
3.创建cglib代理类
/**
* 日志代理
*
* @author huaisf
*
*/
public class LoggerProxy implements MethodInterceptor {
private Object oject;
public LoggerProxy(Object oject) {
this.oject = oject;
}
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(oject.getClass());
// 设置enhancer的回调对象
enhancer.setCallback((Callback) this);
// 创建代理对象
return enhancer.create();
}
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;
}
}
4.编写测试类
public class Test {
public static void main(String[] args) {
OrderServiceImpl target = new OrderServiceImpl();
OrderService proxy = (OrderService) new LoggerProxy(target).getProxyInstance();
proxy.saveOrder();
}
}