代理模式(二)

JDK动态代理

public class Order {
    private Object orderInfo;
    //订单创建时间进行按年分库
    private Long createTime;
    private String id;

    public Object getOrderInfo() {
        return orderInfo;
    }

    public void setOrderInfo(Object orderInfo) {
        this.orderInfo = orderInfo;
    }

    public Long getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Long createTime) {
        this.createTime = createTime;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
public class OrderDao {
    public int insert(Order order){
        System.out.println("OrderDao创建Order成功!");
        return 1;
    }
}
public interface IOrderService {
    int createOrder(Order order);
}
public class OrderService implements IOrderService {
    private OrderDao orderDao;

    public OrderService(){
        //如果使用Spring应该是自动注入的
        //我们为了使用方便,在构造方法中将orderDao直接初始化了
        orderDao = new OrderDao();
    }

    public int createOrder(Order order) {
        System.out.println("OrderService调用orderDao创建订单");
        return orderDao.insert(order);
    }
}
public class OrderServiceDynamicProxy implements InvocationHandler {

    private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");

    Object proxyObj;
    public Object getInstance(Object proxyObj) {
        this.proxyObj = proxyObj;
        Class<?> clazz = proxyObj.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before(args[0]);
        Object object = method.invoke(proxyObj,args);
        after();
        return object;
    }

    private void after() {
        System.out.println("Proxy after method");
        //还原成默认的数据源
        DynamicDataSourceEntity.restore();
    }

    //target 应该是订单对象Order
    private void before(Object target) {
        try {
            //进行数据源的切换
            System.out.println("Proxy before method");

            //约定优于配置
            Long time = (Long) target.getClass().getMethod("getCreateTime").invoke(target);
            Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
            System.out.println("静态代理类自动分配到【DB_" + dbRouter + "】数据源处理数据");
            DynamicDataSourceEntity.set(dbRouter);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
public static void main(String[] args) {
    try {
        Order order = new Order();

         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
         Date date = sdf.parse("2019/04/05");
         order.setCreateTime(date.getTime());
         IOrderService orderService = (IOrderService)new OrderServiceDynamicProxy().getInstance(new OrderService());
         orderService.createOrder(order);
    }catch (Exception e){
        e.printStackTrace();
    }

}

CGLib动态代理容易踩的坑:

1 无法代理final修饰的方法

CGLib和JDK动态代理对比:

1 JDK动态代理是实现了被代理对象的接口,CGLib是继承了被代理对象

2 JDK和CGLib都是在运行期生成字节码,JDK是直接写Class字节码,CGLib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。

3 JDK调用代理方法,是通过反射机制调用,CGLib是通过FastClass机制直接调用方法,CGLib执行效率更高

优点:

1 代理模式能将代理对象与真实被调用的目标对象分离

2 一定程度上降低了系统的耦合程度,易于扩展

3 代理可以起到保护目标对象的作用

4 增强目标对象的职责

缺点:

1 代理模式会造成系统设计中类的数目增加

2 在客户端和目标对象之间增加了一个代理对象,会造成请求处理速度变慢

3 增加了系统的复杂度

Spring中的代理选择原则:

1 当Bean有实现接口时,Spring就会用JDK的动态代理

2 当Bean没有实现接口时,Spring选择CGLib

3 Spring可以通过配置强制使用CGLib,只需在Spring的配置文件中加入如下代码: <aop:aspectj-autoproxy proxy-target-class="true"/>

public class Customer {

    public void findLove(){
        System.out.println("儿子要求:肤白貌美大长腿");
    }
}
public class CGlibMeipo implements MethodInterceptor {


    public Object getInstance(Class<?> clazz) throws Exception{
        //相当于Proxy,代理的工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}
public static void main(String[] args) {

    try {


        //JDK是采用读取接口的信息
        //CGLib覆盖父类方法
        //目的:都是生成一个新的类,去实现增强代码逻辑的功能

        //JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
        //CGLib 可以代理任意一个普通的类,没有任何要求

        //CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
        //JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用

        //CGLib 有个坑,CGLib不能代理final的方法

        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cp_classes");

        Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
        System.out.println(obj);
        obj.findLove();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

 

转载于:https://my.oschina.net/u/2954646/blog/3032905

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值