推荐:Java设计模式汇总
代理模式
定义
代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。
类型
结构型。
例子
我们每次在
Controller层
中实现向数据库
insert数据
,一般都是经过
Service层、Dao层,再到数据库
,这里我们将
Service层
进行代理。
为了简单,有些地方并没有像实际开发一样严格。
Order类(订单类),实体类。
package com.kaven.design.pattern.structural.proxy;
public class Order {
private Object orderInfo;
private Integer userId;
public Object getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(Object orderInfo) {
this.orderInfo = orderInfo;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
IOrderDao接口(Dao层接口),这里没有分不同的包。
package com.kaven.design.pattern.structural.proxy;
public interface IOrderDao {
int insert(Order order);
}
OrderDaoImpl类(Dao层实现类)。
package com.kaven.design.pattern.structural.proxy;
public class OrderDaoImpl implements IOrderDao {
public int insert(Order order) {
System.out.println("Dao层添加Order成功");
return 1;
}
}
IOrderService接口(Service层接口)。
package com.kaven.design.pattern.structural.proxy;
public interface IOrderService {
int saveOrder(Order order);
}
OrderServiceImpl类(Service层实现类)。
package com.kaven.design.pattern.structural.proxy;
public class OrderServiceImpl implements IOrderService {
private IOrderDao iOrderDao;
public int saveOrder(Order order) {
// 使用Spring注解会自己注入,这里就直接new了
iOrderDao = new OrderDaoImpl();
System.out.println("Service层调用Dao层添加Order");
return iOrderDao.insert(order);
}
}
静态代理
OrderServiceStaticProxy类(Service层的静态代理类)。
package com.kaven.design.pattern.structural.proxy.staticproxy;
import com.kaven.design.pattern.structural.proxy.IOrderService;
import com.kaven.design.pattern.structural.proxy.Order;
import com.kaven.design.pattern.structural.proxy.OrderServiceImpl;
public class OrderServiceStaticProxy {
private IOrderService iOrderService;
public int saveOrder(Order order){
//方法增强,比如分库、校验、安全等处理
beforeMethod(order);
iOrderService = new OrderServiceImpl();
int result = iOrderService.saveOrder(order);
//方法增强,比如释放资源等处理
afterMethod();
return result;
}
private void beforeMethod(Order order){
System.out.println("静态代理 before code");
//根据用户ID % 2 的值进行分库
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("静态代理分配到 【db"+dbRouter+"】处理数据");
//TODO 分库操作
}
private void afterMethod(){
System.out.println("静态代理 after code");
}
}
应用层代码:
package com.kaven.design.pattern.structural.proxy.staticproxy;
import com.kaven.design.pattern.structural.proxy.Order;
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
orderServiceStaticProxy.saveOrder(order);
}
}
输出:
静态代理 before code
静态代理分配到 【db0】处理数据
Service层调用Dao层添加Order
Dao层添加Order成功
静态代理 after code
JDK动态代理
OrderServiceDynamicProxy类(Service层的JDK动态代理类)。
从静态代理中可以发现,每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类。所以我们想办法通过一个代理类完成全部的代理功能,那么我们就需要用动态代理。
静态代理是在代码编译后就已经确定被代理的对象了。而动态代理是在代码运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。
在Java中要想实现动态代理机制,
需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类的支持
。
动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler接口,实现invoke方法
。invoke方法就是调用被代理接口的所有方法时需要调用的,返回的值是被代理接口的一个实现类。
package com.kaven.design.pattern.structural.proxy.jdk;
import com.kaven.design.pattern.structural.proxy.Order;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class OrderServiceJDKDynamicProxy implements InvocationHandler {
private Object target;
public OrderServiceJDKDynamicProxy(Object target) {
this.target = target;
}
public Object bind(){
Class cls = target.getClass();
return Proxy.newProxyInstance(cls.getClassLoader() , cls.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target,args);
afterMethod();
return object;
}
private void beforeMethod(Object object){
System.out.println("JDK动态代理 before code");
if(object instanceof Order){
Order order = (Order)object;
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("JDK动态代理分配到 【db"+dbRouter+"】处理数据");
//TODO 分库操作
}
//TODO 其他类型处理
}
private void afterMethod(){
System.out.println("JDK动态代理 after code");
}
}
看不太懂的话,可以先去看一看JDK动态代理相关的博客。
应用层代码:
package com.kaven.design.pattern.structural.proxy.jdk;
import com.kaven.design.pattern.structural.proxy.IOrderService;
import com.kaven.design.pattern.structural.proxy.Order;
import com.kaven.design.pattern.structural.proxy.OrderServiceImpl;
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(1);
IOrderService orderServiceJDKDynamicProxy = (IOrderService) new OrderServiceJDKDynamicProxy(new OrderServiceImpl()).bind();
orderServiceJDKDynamicProxy.saveOrder(order);
}
}
输出:
JDK动态代理 before code
JDK动态代理分配到 【db1】处理数据
Service层调用Dao层添加Order
Dao层添加Order成功
JDK动态代理 after code
CGLib动态代理
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
OrderServiceCGLibDynamicProxy类(Service层的CGLib动态代理类)。
package com.kaven.design.pattern.structural.proxy.cglib;
import com.kaven.design.pattern.structural.proxy.Order;
import com.kaven.design.pattern.structural.proxy.OrderServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class OrderServiceCGLibDynamicProxy implements MethodInterceptor {
public OrderServiceImpl bind(){
Enhancer enhancer = new Enhancer();//生成代理对象
enhancer.setSuperclass(OrderServiceImpl.class);//设置对谁进行代理
enhancer.setCallback(this);//代理要做什么
OrderServiceImpl orderService = (OrderServiceImpl) enhancer.create();//创建代理对象
return orderService;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
beforeMethod(objects[0]);
Object object = methodProxy.invokeSuper(o,objects);
afterMethod();
return object;
}
private void beforeMethod(Object object){
System.out.println("CGLib动态代理 before code");
if(object instanceof Order){
Order order = (Order)object;
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("CGLib动态代理分配到 【db"+dbRouter+"】处理数据");
//TODO 分库操作
}
//TODO 其他类型处理
}
private void afterMethod(){
System.out.println("CGLib动态代理 after code");
}
}
应用层代码:
package com.kaven.design.pattern.structural.proxy.cglib;
import com.kaven.design.pattern.structural.proxy.IOrderService;
import com.kaven.design.pattern.structural.proxy.Order;
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(1);
OrderServiceCGLibDynamicProxy orderServiceCGLibDynamicProxy =
new OrderServiceCGLibDynamicProxy();
IOrderService iOrderService = orderServiceCGLibDynamicProxy.bind();
iOrderService.saveOrder(order);
}
}
输出:
CGLib动态代理 before code
CGLib动态代理分配到 【db1】处理数据
Service层调用Dao层添加Order
Dao层添加Order成功
CGLib动态代理 after code
应用场景
- 应用远程代理控制访问远程对象。
- 虚拟代理控制访问创建开销大的对象。
- 保护代理基于权限控制对资源的访问。
优点
- 实现了访问者与访问对象之间的解耦。
- 代理模式在应用层与对象之间起到中介作用,保护了对对象的访问。
- 代理模式可以在访问过程中增加逻辑,如Spring框架的AOP。
- 增加代理会使程序请求处理变慢。
- 类的数量变多,系统更加复杂。