大纲

  1. 代理
  2. proxy
  3. cglib
  4. 小结

一、代理

为什么要用代理?其实就是希望不修改对象的情况下,增强对象。

静态代理:

  • 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法,调用方法的前后实现需要增强的逻辑。
  • 静态代理有一个问题就是,每个代理类和目标类一一对应,需要代理的类多的情况,需要大量的代理类,难以维护。

动态代理:

  • 动态代理就是运行时动态生成的类,并不是在编译时期。
  • 动态代理有两种不同的方式,一种是jdk反射包下的的Prxoy,一种是cglib。

二、Proxy

Proxy生成代理对象需要目标对象实现一至少一个接口。

Proxy通过反射实现动态代理。

生成代理对象需要调用Proxy中newProxyInstance方法。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

loader-目标对象的classloader

interfaces-目标对象实现的接口

InvocationHandler-处理器,当目标对象接口中的方法被调用时处理器中invoke方法会被调用从而实现动态代理

在看下InvocationHandler

public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

proxy-代理对象
method-被调用的方法
args-调用方法时传入的参数
invoke返回值为代理方法的返回值

测试:

接口:

public interface Speak {
String say(String content);
}

目标类:


import lombok.Data;
@Data
public class Person implements Speak{
private String name;
private int age;
public String say(String content){
System.out.println("hi"+name+age+"content:"+content);
return "say return";
}
}

代理工厂:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyFactory{
//维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//生成代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method:"+method.getName());
//执行目标对象方法,返回return值。
Object returnValue = method.invoke(target, args);
System.out.println("end method:"+method.getName());
return returnValue;
}
});
}
}

代理对象在代理方法调用前后打了一行字。

public static void main(String[] args) {
Person p = new Person();
p.setAge(11);
p.setName("xx");
ProxyFactory factory = new ProxyFactory(p);
Object proxyInstance = factory.getProxyInstance();
Speak speak = (Speak) proxyInstance;
String returnValue = speak.say("haha");
System.out.println("returnValue:"+returnValue);
}

三、cglib

静态代理和都必须实现接口,而cglib没有这个限制,cglib通过字节码操作动态生成子类,因此目标类不能被final修饰。

与proxy类似的我们也需要复写一个处理器

public interface MethodInterceptor extends Callback {
Object  (Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable;
}

proxy-代理对象
method-被调用的方法
methodProxy-代理方法(具体本人不是特别清楚)
intercept返回值为代理方法的返回值

测试:

重写Person不需要实现接口

import lombok.Data;

@Data
public class Person{
private String name;
private int age;
public String say(String content){
System.out.println("hi"+name+age+"content:"+content);
return "say return";
}
}

代理工厂:

import org.assertj.core.internal.cglib.proxy.Enhancer;
import org.assertj.core.internal.cglib.proxy.MethodInterceptor;
import org.assertj.core.internal.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CgProxyFactory<T> {
//维护目标对象
private T target;
public CgProxyFactory(T target) {
this.target = target;
} //获取代理
public T getProxyInstance() {
Enhancer en = new Enhancer();
en.setSuperclass(this.target.getClass());
//设置拦截器
en.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before method:"+method.getName());
Object returnValue = method.invoke(target, objects);
System.out.println("end method:"+method.getName());
return returnValue;
}
});
return (T) en.create();
}
}

和之前的代理对象一样,在代理方法调用前后打了一行字。

public static void main(String[] args) {
Person p = new Person();
p.setAge(11);
p.setName("xx");
CgProxyFactory<Person> factory = new CgProxyFactory(p);
Person proxyInstance = factory.getProxyInstance();
String returnValue = proxyInstance.say("cg");
System.out.println("returnValue:" + returnValue);
}

四、小结:

  1. Proxy需要代理类实现接口,底层为反射。
  2. Cglib代理对象不能被final修饰,底层是字节码操作。
  3. spring会根据目标类是否实现接口的情况,切换动态代理的模式,也可以通过配置强制使用cglib。

java动态代理--proxy&cglib的更多相关文章

  1. java动态代理之CGLIB实现

    动态代理(CGlib 与连接池的案例) Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用. 我们要使用cglib代理必须引入 cglib的jar包 ...

  2. Java动态代理与CGLib

    Java帝国之动态代理 CGLib:从兄弟到父子-动态代理在民间是怎么玩的? 以上两篇文章引用自微信公众号: 码农翻身 Java动态代理 深度详解 以上文章引用博客园:陈树义

  3. Java动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

  4. (转)Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  5. Java动态代理机制——Cglib

    上一篇说过JDK动态代理机制,只能代理实现了接口的类,这就造成了限制.对于没有实现接口的类,我们可以用Cglib动态代理机制来实现. Cglib是针对类生成代理,主要是对用户类生成一个子类.因为有继承 ...

  6. IT忍者神龟之Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  7. java动态代理Proxy

    package com.gz_06; public interface StudentDao { public void login(); public void regist(); } packag ...

  8. java 动态代理 Proxy.newProxyInstance 使用心法

    使用JDk的Proxy类的静态方法newProxyInstance ,让JVM自动生成一个新的类,类中包含了inerfaces参数中的所有方法,每个方法都调用h.invoke 方法       AOP ...

  9. Proxy Pattern(Java动态代理和cglib的实现)

    代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用. 代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务.而 ...

随机推荐

  1. 【记录】原生js日期格式化转换方法

    情况一:将日期转换为指定的格式:比如转换成 年月日时分秒 首先我们在js中定义函数如下 Date.prototype.format = function(fmt) { var o = { " ...

  2. 2019-9-2-win10-uwp-Markdown

    title author date CreateTime categories win10 uwp Markdown lindexi 2019-09-02 12:57:38 +0800 2018-2- ...

  3. 第3篇K8S集群部署

      一.利用ansible部署kubernetes准备: 集群介绍 本系列文档致力于提供快速部署高可用k8s集群的工具,并且也努力成为k8s实践.使用的参考书:基于二进制方式部署和利用ansible- ...

  4. java反射技术主要实现类有哪些,作用分别是什么

    Java反射技术主要实现类有哪些,作用分别是什么? 在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中 1)Class类:代表一个类 2)Field 类 ...

  5. Java自定义注解Annotation的使用

    从 jdk5开始,Java增加了对元数据的支持,也就是Annotation,Annotation其实就是对代码的一种特殊标记,这些标记可以在编译,类加载和运行时被读取,并执行相应的处理.当然刚刚说了, ...

  6. vue-bus全局事件中心简单Demo

    1.vue-cli搭建好项目之后,使用npm安装vue-bus npm install vue-bus 2.在入口文件main.js中全局注册 import Vue from 'vue'; impor ...

  7. elementUI表单嵌套时间报错

    elementUI表单嵌套日期时间选择时间后报错 <el-form-item label="起始结束时间:" required prop="startime&quo ...

  8. TxtUtil

    /** *包名:cn.yufu.utils *描述:package cn.yufu.utils; */ package cn.yufu.utils; import java.io.BufferedRe ...

  9. Android编程:解决异常“android.view.InflateException: Binary XML file line # : Error inflating class”

    今天写程序发现一个问题,就是XML中报出android.view.InflateException异常,可能的原因有: 1.XML中使用到得组件名称是否书写正确(包名+类名),可以使用crtl+鼠标点 ...

  10. 误将SELINUXTYPE看成SELINUX后,将其值改为disabled。导致操作系统服务启动,无法进入单用户模式

    环境:Redhat 6.4 ORACLE11g RAC 在安装ORACLE11g之前需要关闭操作系统的防火墙和SELinux. 1.关闭防火墙:iptables -F————————————清除防火墙 ...