设计模式四、代理模式(静态代理、JDK动态代理、Cglib动态代理、⼿写动态
代理核⼼部分)。。。
代理模式
1、应⽤场景
在⽣活中,我们经常见到这样的场景,如:租房中介、售票黄⽜、婚介、经纪⼈、快递、事务代理、⾮侵⼊式⽇志监听等,这些都是代理模式的实际体现。代理模式(ProxyPattern)的定义也⾮常简单,是指为其他对象提供⼀种代理,以控制对这个对象的访问。代理对象在客服端和⽬标对象之间起到中介作⽤,代理模式属于结构型设计模式。使⽤代理模式主要有两个⽬的:⼀保护⽬标对象,⼆是对对象的某⼀功能的流程把控和辅助。在代码中,我们想到代理,就会理解为是代码增强,其实就是在原本逻辑前后增加⼀些逻辑,⽽调⽤者⽆感知。代理模式属于结构型模式,有静态代理和动态代理两种实现⽅式。
2、静态代理
2.1、⽣活场景举例
举个例⼦:随着互联⽹和OTO模式的发展,⼈们越来越喜欢在家点餐就会有骑⼿⼩哥送餐的外卖形式,
在这个过程中餐厅只能完成制作美⾷,⽽骑⼿⼩哥就是对餐厅卖餐的代理,实现了送餐流程的辅助效果。
我们创建Restaurant.java餐厅接⼝
//餐厅接⼝
public interface Restaurant {
//送餐⽅法
public void foodDelivery();
}
个⼈点外卖还是喜欢⽥⽼师红烧⾁,故创建TianRestaurant.java ⽥⽼师餐厅类实现顶层接⼝
public class TianRestaurant implements Restaurant{
@Override
public void foodDelivery(){
System.out.println("制作美⾷");
}
}
为了达到送餐的⽬的,我们还需要对餐厅的送餐⾏为进⾏代理,故创建RestaurantProxy代理类,在餐厅的送餐⽅法前后,加⼊了代理的功能实现。
public class RestaurantProxy implements Restaurant{
private Restaurant restaurant;
public RestaurantProxy(Restaurant restaurant){
}
public void foodDelivery(){
System.out.println("骑⼿接单");
restaurant.foodDelivery();
System.out.println("骑⼿取餐,送往⽤户");
}
}
创建⽤户调⽤类
public class User {
public static void main(String[] args){
RestaurantProxy restaurantProxy =new RestaurantProxy(new TianRestaurant());
System.out.println("⽤户下单");
restaurantProxy.foodDelivery();
System.out.println("⽤户接餐");
}
}
console打印结果:
⽤户下单
骑⼿接单
制作美⾷
骑⼿取餐,送往⽤户
⽤户接餐
2.2、实际功能场景举例
上述例⼦为⽣活中场景的代理模式的实现,再来例举下在代码功能层次的实现。
在分布式业务场景中,我们通常会按照某种分配规则对数据库进⾏分库分表,分库分表之后使⽤ Java
操作时,就可能需要配置多个数据源,我们通过设置数据源路由来动态切换数据源。我们通过实际场景中的三层结构来模拟插⼊订单数据实现动态切换数据源的效果。
创建订单实体类Order.java
/**
* 订单实体类
*/
public class Order {
//订单主键
private Integer id;
//订单号
private String orderSn;
//订单⾦额
private BigDecimal price;
public Integer getId(){
return id;
}
public void setId(Integer id){
this.id = id;
}
public String getOrderSn(){
return orderSn;
}
public void setOrderSn(String orderSn){
}
public BigDecimal getPrice(){
return price;
}
public void setPrice(BigDecimal price){
this.price = price;
}
public Order(Integer id, String orderSn, BigDecimal price){
this.id = id;
this.price = price;
}
bigdecimal转换为integer}
创建DAO持久层接⼝OrderDao.java
public interface OrderDao {
public void insertOrder(Order order);
}
创建其实现类OrderDaoImpl.java
public class OrderDaoImpl implements OrderDao{
@Override
public void insertOrder(Order order){
System.out.println("插⼊订单成功,使⽤的数据源为"+()); }
}
创建service层接⼝OrderService.java
public interface OrderService {
public void insertOrder(Order order);
}
创建OrderServiceImpl.java实现上述接⼝,,同时使⽤关联关系将OrderDao引⼊,调⽤其insertOrder⽅法
public class OrderServiceImpl implements OrderService{
private OrderDao orderDao;
public OrderServiceImpl(OrderDao orderDao){
}
@Override
public void insertOrder(Order order){
orderDao.insertOrder(order);
}
}
接下来使⽤静态代理,主要完成的功能是,根据订单的主键是否为偶数将其分为两个数据源。根据开闭原则,原来写好的逻辑我们不去修改,通过代理对象来完成。先创建数据源路由对象,我们使⽤ ThreadLocal 的单例实现,DataSource类
public class DataSource {
//模拟单数数据源
public final static String SINGULAR ="Singular";
//模拟偶数数据源
public final static String EVENNUMBERS ="EvenNumbers";
//默认数据源为null
public final static String DEFAULT = null;
private final static ThreadLocal<String> local =new ThreadLocal<String>();
private DataSource(){};
public static void set(String dataSourceName){
local.set(dataSourceName);
}
public static String get(){
();
}
public static void reset(){
local.set(DEFAULT);
}
public static void clear(){
}
}
然后通过静态代理来实现对原有的订单插⼊⽅法的流程把握,加⼊辅助功能,创建OrderDaoProxy代理类
public class OrderDaoProxy implements OrderDao{
private OrderDao orderDao;
public OrderDaoProxy(OrderDao orderDao){
}
@Override
public void insertOrder(Order order){
//订单的主键为偶数,则使⽤偶数数据源
Id()%2==0){
DataSource.set(DataSource.EVENNUMBERS);
}else{
//为奇数,使⽤奇数数据源
DataSource.set(DataSource.SINGULAR);
}
orderDao.insertOrder(order);
//重置数据源
}
}
来看测试代码:
public class DataSourceTest {
public static void main(String[] args){
OrderService orderServiceImpl =new OrderServiceImpl(new OrderDaoProxy(new OrderDaoImpl())); orderServiceImpl.insertOrder(new Order(2,"123",new BigDecimal("21.21")));
}
}
运⾏结果:
插⼊订单成功,使⽤的数据源为EvenNumbers
将订单的id变成奇数,运⾏结果:
插⼊订单成功,使⽤的数据源为Singular
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论