当前位置:首页 > CN2资讯 > 正文内容

深入剖析动态代理(上)之代理的方式java动态代理的实现方式

1天前CN2资讯


    关于动态代理,大家显式使用的可能比較少,可是说到Spring的Interceptor、各种各样的事务管理,大家会更熟悉一些,没错,这些在底层实现上,都是使用的动态代理,确切的说,想要为一个类的方法,动态加入功能,比方验证、资源释放、日志处理等,大部分都是借助动态代理。

    为了平缓的过渡,先来说一下静态代理。

静态代理

    静态代理的思路非常easy:把一个真实对象的实例放到代理对象的实例中。然后调用代理对象方法,代理对象的方法调用真实对象的方法,以事务管理为例。例如以下:

    UserDao

package com.tgb.staticproxy;

public interface UserDao {

public void add();
public void deleteAll();
}

    UserDaoImpl

package com.tgb.staticproxy;

public class UserDaoImpl implements UserDao {

public void add()
{
System.out.println("加入一名用户到数据库");
}
public void deleteAll()
{
System.out.println("删除全部用户");
}
}

    UserDaoProxy

package com.tgb.staticproxy;

public class UserDaoProxy implements UserDao {

UserDao userDao=null;
public UserDaoProxy(UserDao userDao)
{
this.userDao=userDao;
}

public void add()
{
System.out.println("开启本地事务");
userDao.add();
System.out.println("提交或回滚事务");
}
public void deleteAll()
{
System.out.println("开启本地事务");
userDao.deleteAll();
System.out.println("提交或回滚事务");
}
}

    Test

package com.tgb.staticproxy;

public class Test {

/**
* @param args
*/
public static void main(String[] args) {

UserDao userDao=new UserDaoImpl();
UserDaoProxy userDaoProxy=new UserDaoProxy(userDao);

//測试加入
userDaoProxy.add();
System.out.println("..........分隔符..........");
//測试删除
userDaoProxy.deleteAll();

}

}

    运行结果

开启本地事务
加入一名用户到数据库
提交或回滚事务
..........分隔符..........
开启本地事务
删除全部用户
提交或回滚事务


    可是静态代理管理事务的方式问题非常大,每一个Dao类的每一个方法都须要开启和关闭事务,不仅代码反复严重,而事务本来是和业务没什么关联,却耦合到一起。

动态代理

    JDK动态代理

    相同以事务管理为例,例如以下:

    UserDao

package com.tgb.dynamicproxy;

public interface UserDao {

public void add();
public void deleteAll();
}

    UserDaoImpl

package com.tgb.dynamicproxy;

public class UserDaoImpl implements UserDao {

@Override
public void deleteAll() {
System.out.println("删除全部用户信息");
}
@Override
public void add() {
System.out.println("加入一名用户到数据库");
}

}

    Handler

package com.tgb.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Handler implements InvocationHandler {

private Object target;

public Handler(Object target)
{
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//开启事务
before();
//运行业务
method.invoke(target, args);
//提交或回滚事务
after();

return null;
}
public void before()
{
System.out.println("開始本地事务");
}
public void after()
{
System.out.println("提交或回滚事务");
}
}

    Test

package com.tgb.dynamicproxy;

import java.lang.reflect.Proxy;

public class Test {

/**
* @param args
*/
public static void main(String[] args) {
try{
UserDao impl=new UserDaoImpl();
Handler handler=new Handler(impl);
UserDao proxy=(UserDao)Proxy.newProxyInstance
(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), handler);

//測试加入
proxy.add();
System.out.println("..........分隔符..........");
//測试删除
proxy.deleteAll();
}
catch(Exception e)
{
e.printStackTrace();
}

}

}

    运行结果

開始本地事务
加入一名用户到数据库
提交或回滚事务
..........分隔符..........
開始本地事务
删除全部用户信息
提交或回滚事务

    JDK的动态代理克服了静态代理耦合和代码反复的问题,可是JDK的代理模式有个比較严重的问题。如UserDao必需要有接口才干够使用JDK动态代理,这就大大限制了JDK动态代理的范围。

cglib动态代理


    asm能够动态生成字节码,cglib对asm进行了再封装,cglib并非为了动态代理而生的,可是利用它的特性。却能够非常好的实现动态代理。
UserDaoImpl
package com.tgb.cglib;

public class UserDaoImpl {

public void deleteAll() {
System.out.println("删除全部用户信息");
}

public void add() {
System.out.println("加入一名用户到数据库");
}

}CglibProxypackage com.tgb.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {

private Object target;
private CglibProxy(Object target){
this.target = target;
}
//产生代理对象
@SuppressWarnings("unchecked")
public static <T> T proxyTarget(T t){

Enhancer en = new Enhancer();
en.setSuperclass(t.getClass());
en.setCallback((Callback) new CglibProxy(t));
T tt = (T) en.create();
return tt;

}

//运行拦截
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {

System.out.println("开启本地事务");
Object o = method.invoke(target, args);
System.out.println("提交或回滚事务");
return o;
}
}Testpackage com.tgb.cglib;

public class Test {

/**
* @param args
*/
public static void main(String[] args) {
//获代替理对象
UserDaoImpl impl=CglibProxy.proxyTarget(new UserDaoImpl());
//測试加入
impl.add();
System.out.println("..........分隔符..........");
//測试删除
impl.deleteAll();
}

}执行结果开启本地事务
加入一名用户到数据库
提交或回滚事务
..........分隔符..........
开启本地事务
删除全部用户信息
提交或回滚事务


    能够看到,这次UserDaoImpl并没有实现不论什么接口接口实现动态代理的功能。
总结   这篇博客本来打算写JDK和cglib动态代理的源代码介绍的。写着写着就写成介绍代理都有哪些类型及实现方式了,再写篇幅就有点长了。所以放到下篇博客说明。






    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/32102.html

    分享给朋友:

    “深入剖析动态代理(上)之代理的方式java动态代理的实现方式” 的相关文章

    续费同价服务器:云服务的透明定价策略与用户优势

    续费同价服务器是什么呢?说白了,就是云服务提供商在定价上采取的一种政策。无论是新用户第一次购买,还是老用户续费,价格都是一样的。这种做法让很多用户感到安心,不用担心下次续费时价格会大幅上涨。这一策略在云服务行业越来越受到重视,也给用户带来了不少好处。 首先,续费同价服务器让价格变得透明。我之前在选择...

    选择日本不限流量VPS的最佳方案与优化建议

    日本不限流量VPS市场现状 日本的VPS市场,尤其是不限流量的产品,正迎来一个快速发展的阶段。随着互联网技术的进步,亚洲的网络环境发生了翻天覆地的变化。尤其是在日本,不限流量VPS因其连接速度快、数据中心服务优质而广受欢迎,对那些需要持续大流量的网站运营者来说,这可是一个无与伦比的选择。 我发现,随...

    高性能HKT VPS服务评测与应用指南

    HKT VPS概述 什么是HKT VPS HKT VPS其实就是基于香港HKT网络架构的虚拟专用服务器,提供了强大的性能和灵活的可配置性。我从多个服务商的不同产品中了解到,HKT VPS非常适合对网络速度和稳定性要求较高的用户。无论是游戏玩家还是企业用户,都能通过它享受到快速的上传和下载速度。 HK...

    甲骨文云免费IPv6服务详解:轻松配置与应用技巧

    甲骨文云,作为一个综合性的云服务提供商,正迅速崛起于众多的云技术平台之中。它不仅拥有强大的数据处理能力,还提供了多种免费的云服务选项,让个人和企业都能以更低的成本探索并使用云计算的强大功能。首先,我对甲骨文云的快速适应能力和多种灵活服务感到印象深刻,尤其是它的免费套餐项目,吸引了不少用户前来试用。...

    Rndc2的线路怎么样?全面评测RackNerd洛杉矶DC02机房

    Rndc2的基本线路信息 说到Rndc2的线路,首先让我跟大家分享一下它的基本信息。这个线路的核心在于RackNerd洛杉矶DC02机房,位置恰好在美国西海岸的洛杉矶。成立于2019年的RackNerd,以其价格优势著称,给我们提供了比较便宜的美国VPS选择,最低年付大约10美元,这对于很多希望节省...

    HostHatch怎么样?全面评测云服务提供商的性能与性价比

    我们今天要聊聊HostHatch,这个相对年轻却迅速崛起的云服务提供商。简单来说,HostHatch成立于不久前,目标是为用户提供高效、经济的托管服务。他们的理念十分清晰,就是希望能让更多的人无需复杂的技术知识,也能轻松享受到稳定高效的服务器服务。 HostHatch的创始团队由一群充满激情的科技爱...