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的实现)
代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用. 代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务.而 ...
随机推荐
- KiCAD层颜色修改
KiCAD层颜色修改 KiCAD的PCB各层的颜色太过于暗淡,有时可能不适合操作者的习惯,尤其是铜层(布线层),这时候就需要去修改层的颜色,具体操作如下图:选择想要修改的层,双击左边颜色框框,进入之后 ...
- 前端学习(十二)js数据类型(笔记)
选项卡: for循环 for(初始值,条件,自增){} for(var i=0; i<9;i++){} 几个按钮对应相同个内容!!! -------------------- ...
- 利用Process类创建多个子进程对象执行任务,主进程负责调度
import time from multiprocessing import Process def run1(): for i in range(5): print("sunck is ...
- psecurity配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...
- asp.net MVC遇到的问题
参考:http://blog.csdn.net/chenqiangdage/article/details/48996101 asp.netMVC 如何解决“上下文模型已在数据库创建后发生更改” 问题 ...
- Read Committed
在Read Committed隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题. 不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一 ...
- Django项目:CRM(客户关系管理系统)--84--74PerfectCRM实现CRM权限和权限组限制访问URL
#models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...
- CSS:CSS Id 和 Class选择器
ylbtech-CSS:CSS Id 和 Class选择器 1.返回顶部 1. CSS Id 和 Class id 和 class 选择器 如果你要在HTML元素中设置CSS样式,你需要在元素中设置& ...
- CSS:CSS 表格
ylbtech-CSS:CSS 表格 1.返回顶部 1. CSS 表格 使用 CSS 可以使 HTML 表格更美观. Company Contact Country Alfreds Futterkis ...
- ()获取Cookies session
[HttpGet] public string mo() { var httpRequest = HttpContext.Current.Request; var a = httpRequest.Co ...