java动态代理--proxy&cglib
大纲
- 代理
- proxy
- cglib
- 小结
一、代理
为什么要用代理?其实就是希望不修改对象的情况下,增强对象。
静态代理:
- 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法,调用方法的前后实现需要增强的逻辑。
- 静态代理有一个问题就是,每个代理类和目标类一一对应,需要代理的类多的情况,需要大量的代理类,难以维护。
动态代理:
- 动态代理就是运行时动态生成的类,并不是在编译时期。
- 动态代理有两种不同的方式,一种是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);
}
四、小结:
- Proxy需要代理类实现接口,底层为反射。
- Cglib代理对象不能被final修饰,底层是字节码操作。
- spring会根据目标类是否实现接口的情况,切换动态代理的模式,也可以通过配置强制使用cglib。
java动态代理--proxy&cglib的更多相关文章
- java动态代理之CGLIB实现
动态代理(CGlib 与连接池的案例) Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用. 我们要使用cglib代理必须引入 cglib的jar包 ...
- Java动态代理与CGLib
Java帝国之动态代理 CGLib:从兄弟到父子-动态代理在民间是怎么玩的? 以上两篇文章引用自微信公众号: 码农翻身 Java动态代理 深度详解 以上文章引用博客园:陈树义
- Java动态代理与Cglib库
JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
- (转)Java动态代理与CGLib代理
<br>public class UserDAOImpl{ <br><br> public void save() { <br> / ...
- Java动态代理机制——Cglib
上一篇说过JDK动态代理机制,只能代理实现了接口的类,这就造成了限制.对于没有实现接口的类,我们可以用Cglib动态代理机制来实现. Cglib是针对类生成代理,主要是对用户类生成一个子类.因为有继承 ...
- IT忍者神龟之Java动态代理与CGLib代理
<br>public class UserDAOImpl{ <br><br> public void save() { <br> / ...
- java动态代理Proxy
package com.gz_06; public interface StudentDao { public void login(); public void regist(); } packag ...
- java 动态代理 Proxy.newProxyInstance 使用心法
使用JDk的Proxy类的静态方法newProxyInstance ,让JVM自动生成一个新的类,类中包含了inerfaces参数中的所有方法,每个方法都调用h.invoke 方法 AOP ...
- Proxy Pattern(Java动态代理和cglib的实现)
代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用. 代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务.而 ...
随机推荐
- tee - 从标准输入写往文件和标准输出
总览 (SYNOPSIS) tee [OPTION]... [FILE]... 描述 (DESCRIPTION) 把 标准输入 的 数据 复制到 每一个 文件 FILE, 同时 送往 标准输出. -a ...
- python smtp发邮件报错“[Errno -2] Name or service not known”的解决
最近给ss-py-mu写了个检查用户是否到期,并在到期前的第2天邮件提醒的功能. 配置存储在ini文件中,通过configparser模块获取,但尝试发送邮件的时候发现报错[Errno -2] Nam ...
- virtualbox ubuntu 磁盘大小扩容
前言 虚拟机软件: virtuabox 虚拟机运行的系统: Ubuntu 18.04.3 desktop 如果需要扩容的虚拟机在运行中,请将需要扩容的虚拟机进行关机 方法 先设置虚拟机的虚拟硬盘的大小 ...
- webpack devServer配置项的坑
本文所用webpack版本为4+,阅读本章的同学请注意区分. webpack默认不需要配置文件 但是你仍可在项目的node_module目录同级目录建立一个webpack.config.js文件进行配 ...
- 使用appium1.4在android8.0真机上测试程序时报错command failed shell "ps 'uiautomator'"的解决方式
appium1.4,运行自动化脚本时提示 org.openqa.selenium.SessionNotCreatedException: A new session could not be crea ...
- Java 基础 - System.arraycopy() 浅拷贝 深拷贝
ref: https://blog.csdn.net/balsamspear/article/details/85069207 https://blog.csdn.net/balsamspear/ar ...
- clickhouse核心引擎MergeTree子引擎
在clickhouse使用过程中,针对数据量和查询场景,MergeTree是最常用也是较为合适的表引擎.针对特定的业务,MergeTree的子引擎可以针对不同的业务而定,但都基于MergeTree引擎 ...
- python3 投票
import urllib.request # cd C:\Python36-32\Scripts # pip install BeautifulSoup from bs4 import Beauti ...
- img引用网络图片资源无法加载问题解决
近期在自己项目中遇到引用一些网络图片资源,显示无法加载,但是在浏览器打开图片路径又可以显示的问题 解决办法: 在图片显示的界面把meta referrer标签改为never <meta name ...
- JSP自定义标签(转)
1. TagSupport与BodyTagSupport的区别 TagSupport与BodyTagSupport的区别主要是标签处理类是否需要与标签体交互,如果不需要交互的就用TagSupport, ...