定义: 为其他对象提供一种代理,以控制对这个对象的访问
代理对象在客户端和目标对象之间起到中介的作用
类型: 结构性
适用场景
1、保护目标对象
2、增强目标对象
优点
代理模式能将代理对象与真实被调用的目标对象分离
一定程度上降低了系统的耦合度,扩展性好
保护目标对象
增强目标对象(如加before和after)
缺点:
代理模式会造成系统设计中类数目增加
在客户端和目标对象增加一个代理对象,会造成请求速度变慢
增加系统的复杂度
代理-扩展
静态代理
动态代理
CGLib代理
Spring 代理选择-扩展
当Bean有实现接口时,Spring就会用JDK的动态代理
当Bean没有实现接口时,Spring使用CGlib
可以强制使用Cglib
在spring配置中加入 <aop:aspectj-autoproxy proxy-target-class="true" />
静态代理实践1、创建实体Order
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;
}
}
2、创建Dao层
IOrderDao接口
public interface IOrderDao {
int insert(Order order);
}
IOrderDao接口实现
public class OrderDaoImpl implements IOrderDao {
@Override
public int insert(Order order) {
System.out.println("Dao层添加Order成功");
return 1;
}
}
3、创建服务层
创建IOrderService 接口
public interface IOrderService {
int saveOrder(Order order);
}
创建IOrderService 接口实现
public class OrderServiceImpl implements IOrderService{
private IOrderDao iOrderDao;
@Override
public int saveOrder(Order order) {
//Spring会自己注入,这里就直接注入了
iOrderDao = new OrderDaoImpl();
System.out.println("Service层调用Dao层添加Order");
return iOrderDao.insert(order);
}
}
4、模拟Spring中分库的使用介绍
创建DynamicDataSource
public class DynamicDataSource extends AbstractRoutingDataSource{
/**
* 返回值代表使用哪个Db
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDBType();
}
}
创建DataSourceContextHolder
public class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void setDBType(String dbType){
CONTEXT_HOLDER.set(dbType);
}
public static String getDBType(){
return (String) CONTEXT_HOLDER.get();
}
public static void clearDBType(){
CONTEXT_HOLDER.remove();
}
}
5、创建代理类
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");
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("静态代理分配到【db" + dbRouter + "】处理数据");
// TODO: 2020/1/27 设置dataSource
DataSourceContextHolder.setDBType("db" + String.valueOf(dbRouter));
}
private void afterMethod(){
System.out.println("静态代理 after code");
}
}
6、测试
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
orderServiceStaticProxy.saveOrder(order);
}
}
7、UML图如下
8、输出结果如下
静态代理 before code
静态代理分配到【db0】处理数据
静态代理 after code
Service层调用Dao层添加Order
Dao层添加Order成功
动态代理实践1、创建动态代理类
public class OrderServiceDynamicProxy implements InvocationHandler{
private Object target;
public OrderServiceDynamicProxy(Object target){
this.target = target;
}
public Object build(){
Class cls = target.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces() ,this);
}
@Override
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 obj){
int userId = 0;
System.out.println("动态代理 before code");
if(obj instanceof Order){
Order order = (Order)obj;
userId = order.getUserId();
}
int dbRouter = userId % 2;
System.out.println("动态代理分配到【db" + dbRouter + "】处理数据");
// TODO: 2020/1/27 设置dataSource
DataSourceContextHolder.setDBType("db" + String.valueOf(dbRouter));
}
private void afterMethod(){
System.out.println("动代理 after code");
}
}
2、测试
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
IOrderService orderServiceDynamicProxy = (IOrderService)new OrderServiceDynamicProxy(new OrderServiceImpl()).build();
orderServiceDynamicProxy.saveOrder(order);
}
}
3、输出
动态代理 before code
动态代理分配到【db0】处理数据
Service层调用Dao层添加Order
Dao层添加Order成功
动代理 after code
代理模式在源码中的应用
1、JDK中的java .lang.reflet.Proxy类
2、Spring中的ProxyFactoryBean
核心的方法为getObject()
还有JdkDynamicAopProxy和CglibAopProxy
3、Mybatis中
MapperProxyFactory