动态代理:为一堆interface或类的实现提供统一的执行通道,从含义上就像局域网电脑通过代理上网一样,走统一的通道,代理控制通道,自然可以在通道里加上自定义实现,例如像AOP切面,日志等。

JDK的动态代理只能对接口实现,代理类需要实现InvocationHandler 接口。

一、接口

public interface UserService {
User addUser();
void editUser(User user);
int deleteUser(int userId);
} //假设有这么一个User类
public class User {
private Integer userId;
private String userName;
private String password; public Integer getUserId() {
return userId;
} public void setUserId(Integer userId) {
this.userId = userId;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} @Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}

二、接口的实现

public class UserServiceImpl implements UserService {
@Override
public User addUser() {
User user = new User();
user.setUserId(1);
user.setUserName("userTest");
user.setPassword("123456");
System.out.println("------> add user");
return user;
} @Override
public void editUser(User user) {
System.out.println("------> edit user:" +user);
} @Override
public int deleteUser(int userId) {
System.out.println("------> delete user:"+userId);
return 1;
}
}

三、JDK代理类实现InvocationHandler

public class ProxyHandler implements InvocationHandler {

    //被代理对象
private Object proxied; public ProxyHandler(Object proxied) {
this.proxied = proxied;
} private void beforeInvoke(String msg)
{
System.out.println("-------> beforInvoke:"+msg);
} private void afterInvoke(String msg)
{
System.out.println("-------> afterInvoke:"+msg);
} private String convertArgs(Object[] args)
{
if(args==null || args.length==0)
{
return null;
}
StringBuilder sb= new StringBuilder();
for(Object object : args)
{
sb.append(object.toString());
} return sb.toString();
} //proxy是代理对象,可以想象成代理服务器
//proxied是被代理对象,可以想象成局域网里的PC
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeInvoke("proxy name:"+proxy.getClass().getName());
beforeInvoke("proxied name:"+proxied.getClass().getName());
beforeInvoke( "args:"+convertArgs(args));
Object o = method.invoke(proxied,args);
afterInvoke("result:"+o);
return o;
}
}

四、使用,实现原理是反射

public class Main {

    public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxyUserService = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new ProxyHandler(userService)
); User user = proxyUserService.addUser(); proxyUserService.editUser(user); proxyUserService.deleteUser(user.getUserId()); }
}

五、结果:符合预期的输出

六、简化一下写法,代理类的生成方式

public class DynamicProxy implements InvocationHandler {
private Object proxied; private void beforeInvoke(String msg)
{
System.out.println("-------> beforInvoke:"+msg);
} private void afterInvoke(String msg)
{
System.out.println("-------> afterInvoke:"+msg);
} private String convertArgs(Object[] args)
{
if(args==null || args.length==0)
{
return null;
}
StringBuilder sb= new StringBuilder();
for(Object object : args)
{
sb.append(object.toString());
} return sb.toString();
}

  //在这里就把代理对象创建出来
public Object getProxyObject(Object proxied) {
this.proxied = proxied;
return Proxy.newProxyInstance(
this.proxied.getClass().getClassLoader(),
this.proxied.getClass().getInterfaces(),
this
);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeInvoke("proxy name:"+proxy.getClass().getName());
beforeInvoke("proxied name:"+proxied.getClass().getName());
beforeInvoke( "args:"+convertArgs(args));
Object o = method.invoke(proxied,args);
afterInvoke("result:"+o);
return o;
}
} //main
public class Main { public static void main(String[] args) { System.out.println("##############"); System.out.println("-------> second call:"); UserService userService = (UserService) new DynamicProxy().getProxyObject(new UserServiceImpl());
User user1 = userService.addUser();
userService.editUser(user1);
userService.deleteUser(user1.getUserId());
}
}

六、使用cglib动态代理

cglib可以代理非接口类,但是因为其实现原理是继承,所以无法代理被代理类中final方法,也无法代理final修饰的类。

代理类需要实现MethodInterceptor 接口

    <dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.8</version>
</dependency> </dependencies> public class CglibDynamicProxy implements MethodInterceptor {
private Object proxied; //Generate a new class if necessary and uses the specified callbacks (if any) to create a new object instance.
//Uses the no-arg constructor of the superclass.
//动态生成一个新的类,使用父类的无参构造方法创建一个指定了特定回调的代理实例
public Object getProxyObject(Object proxied)
{
this.proxied = proxied;
//增强器,动态代码生成器
Enhancer enhancer = new Enhancer();
//回调方法
enhancer.setCallback(this);
//设置生成类的父类类型
enhancer.setSuperclass(proxied.getClass());
//动态生成字节码并返回代理对象
return enhancer.create();
} public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { beforeInvoke("Object:"+o.getClass().getName());
beforeInvoke("method:"+method.getName());
beforeInvoke("args:"+convertArgs(objects));
beforeInvoke("methodProxy:"+methodProxy.getSignature());
Object result = methodProxy.invoke(this.proxied,objects);
afterInvoke("result:"+result);
return result;
} private void beforeInvoke(String msg)
{
System.out.println("-------> beforInvoke:"+msg);
} private void afterInvoke(String msg)
{
System.out.println("-------> afterInvoke:"+msg);
} private String convertArgs(Object[] args)
{
if(args==null || args.length==0)
{
return null;
}
StringBuilder sb= new StringBuilder();
for(Object object : args)
{
sb.append(object.toString());
} return sb.toString();
}
}

main:

public class Main {

    public static void main(String[] args) {

        System.out.println("##############");

        System.out.println("-------> 4 call:");
UserService service4 = (UserService)new CglibDynamicProxy().getProxyObject(new UserServiceImpl());
User user4 = service4.addUser();
service4.editUser(user4);
service4.deleteUser(user4.getUserId()); }
}

java动态代理(JDK和CGLIB)笔记的更多相关文章

  1. CGLIB和Java动态代理的区别(笔记)

    java常用知识点: 1.Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承):CGLIB能够代理普通类:2.Jav ...

  2. 动态代理jdk和cglib的区别

    学习来源贴:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类, ...

  3. 动态代理(JDK、CGLIB)

    JDK-Proxy(动态代理): 特点:要求被代理的对象必须接口 缺点:如果一个对象没有任何接口实现,则不能使用JDK动态代理 1.创建一个Animal 提供一个方法 2.创建一个cat类.实现Ain ...

  4. Java动态代理-JDK自带实现

    上篇文章讲解了什么是静态代理,但是静态代理有一个问题就是需要建立很多的代理类,这样我们需要修改代理的方法的时候,需要在每个类中都要修改,这对于我们来说:当代理类很多的时候工作量就会成倍的增加. 于是针 ...

  5. Java动态代理 ----- jdk代理与cglib代理

    1.jdk代理 针对接口进行代理,接口可以没有方法, InvocationHandler会拦截所有方法,不过好像意义不大....只能执行Object类的方法,执行结果有点奇怪... package t ...

  6. [转]java动态代理(JDK和cglib)

    转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理 ...

  7. java动态代理(JDK和cglib)

    转:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代 ...

  8. 《转》JAVA动态代理(JDK和CGLIB)

    该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的 ...

  9. 《转》java动态代理(JDK和cglib)

    该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的 ...

  10. java动态代理(JDK和cglib实现对比)

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt214 JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特 ...

随机推荐

  1. Spring的定时任务(任务调度)<task:scheduled-tasks>

    Spring内部有一个task是Spring自带的一个设定时间自动任务调度,提供了两种方式进行配置,一种是注解的方式,而另外一种就是XML配置方式了.注解方式比较简洁,XML配置方式相对而言有些繁琐, ...

  2. 转:Docker创建centos的LNMP镜像

    转自:http://www.vckai.com/p/29  1. 安装docker 这个就不说了,不会的可以看下我之前的文章<Docker介绍及安装>. 1)启动docker # serv ...

  3. 关于 Windows 10 字体安装目录的问题

    不知从什么时候开始,本人台式机的Win10系统在安装字体的时候并不是安装到C:\Windows\Fonts目录中,而是安装到%USERPROFILE%\AppData\Local\Microsoft\ ...

  4. 关于 NPOI 导出的 Excel 出现“部分内容有问题” 的解决方法

    近期发现使用 NPOI 导出的 Excel 文件,有部分用户反映在打开时报错,测试了一下,发现在低版本的 Office 中(2003版,配合2007格式兼容包)打开正常,但在高版本 Office 中, ...

  5. 「日常训练」Woodcutters(Codeforces Round 303 Div.2 C)

    这题惨遭被卡..卡了一个小时,太真实了. 题意与分析 (Codeforces 545C) 题意:给定\(n\)棵树,在\(x\)位置,高为\(h\),然后可以左倒右倒,然后倒下去会占据\([x-h,x ...

  6. 刚安装的Linux Centos7使用yum安装firefox时提示:cannot find a valid baseurl for repo

    出现这个问题是因为yum在安装包的过程中,虽然已经联网,但是没法解析远程包管理库对应的域名,所以我们只需要在网络配置中添加上DNS对应的ip地址即可. 解决参考链接:https://blog.csdn ...

  7. Qt PC 安卓 tcp传输文件

    废话不多说,如题,上代码 qt PC端 头文件 //网络部分 #include <QTcpSocket> #include <QFile> #include <QFile ...

  8. python里pickle模块

    Pickle模块用于将复杂的文件转化为二进制的文件 pickle模块一般是在源代码里面含有较大的字典或者列表等复杂文件时,我们如果将文件直接写在源代码里面,这样会使得代码很冗余,并且源代码文件所占空间 ...

  9. jdk从1.8换成1.7后,查看版本还是1.8解决方法

    因学习需要,需将jdk从1.8更改到1.7,其中遇到了些小麻烦,如果你也遇到这种麻烦,可以借鉴一下我的解决方法. 1.jdk的安装及环境变量的配置,详见https://jingyan.baidu.co ...

  10. Thunder团队第二周 - Scrum会议6

    Scrum会议6 小组名称:Thunder 项目名称:爱阅app Scrum Master:宋雨 工作照片: 邹双黛同学在拍照,所以不再照片中. 参会成员: 王航:http://www.cnblogs ...