Python 官方文档:入门教程 => 点击学习
目录一、代理设计模式1.1 什么是代理1.2 代理模式入门二、Java代理的三种实现2.1 静态代理2.2 Java自带的动态代理2.3 cglib实现动态代理三
query()
方法query()
方法中,代码首部获取startTime,代码尾部获取endTime,通过打印日志的方式,知道每次查询的耗时
long startTime = System.currentTimeMillis();
logger.info("query mysql start:" + new Date(startTime).toLocaleString());
// 具体的query代码
...
long endTime = System.currentTimeMillis();
logger.info(String.fORMat("query mysql end: %s, consumed time: %dms", new Date(endTime).toLocaleString(), (endTime-startTime)));
(1)现在是打印日志,代码非常简单,就算query()
方法不是你实现的,你也能很好的完成。
(2)但是如果是其他功能呢?比如,如果查询失败,要求你查询重试
query()
方法前提下,去实现日志打印的功能是最好的方法。包装
类。(1)这个包装
类与实现类一样,实现了相同的接口。
(2)在query()
方法中,直接调用实现类的query()
方法,并在调用前后进行日志打印
(3)对实现类方法的调用,都改成对包装
类方法的调用
long startTime = System.currentTimeMillis();
logger.info("query mysql start:" + new Date(startTime).toLocaleString());
// 使用try-finally
JSONObject[] data = null;
try {
data = mysql.query();
return data;
} catch (Exception exception) {
throw exception;
} finally {
long endTime = System.currentTimeMillis();
logger.info(String.format("query mysql end: %s, consumed time: %dms", new Date(endTime).toLocaleString(), (endTime - startTime)));
}
代理模式的UML图如下
1.subject:
抽象主题角色,是一个接口,定义了一系列的公共对外方法
2.real subject:
真实主题角色,也就是我刚刚提到的实现类,又称委托类。
委托类实现抽象主题,负责实现具体的业务逻辑
3.proxy:
代理主题角色,简称代理类。它也实现了抽象主题,用于代理、封装,甚至增强委托类。
一般通过内含委托类,实现对委托类的封装
4.client:
当访问具体的业务逻辑时,clinet表面是访问代理类,而实际是访问被代理类封装的委托类
代理模式的应用场景:目前,就我本人所接触的使用场景,就是通过代理去打印日志、增强业务逻辑 😂
(1)静态是指字节码,即class文件,在编译时就已经生成。
(2)动态是指字节码在运行时动态生成,而不是编译时提前生成
下面是一个具体的静态代理实例:
抽象主题:
public interface Animal {
void eat();
}
委托类:Dog和Cat,实现了抽象接口
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("I like eating bone");
}
}
public class Cat implements Animal {
@Override
public void eat() {
System.out.println("I like eating fish");
}
}
代理类:代理类中含有对应的委托类,通过调用委托类的具体实现,来封装委托类
public class DogProxy implements Animal {
private Dog dog;
public DogProxy(Dog dog) {
this.dog = dog;
}
@Override
public void eat() {
System.out.print("I'm a "+dog.getClass().getSimpleName() +". ");
dog.eat();
}
}
public class CatProxy implements Animal {
private Cat cat;
public CatProxy(Cat cat) {
this.cat = cat;
}
@Override
public void eat() {
System.out.print("I'm a " + cat.getClass().getSimpleName()+". ");
cat.eat();
}
}
静态代理虽然实现简单、不更改原始的业务逻辑,但是仍然存在以下缺点:
1.如果存在多个委托类,则需要创建多个代理类,这样则会产生过多的代理类。
2.如果抽象主题增加、删除、修改方法时,委托类和代理类都需要同时修改,不易维护。
java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
类,可以实现动态代理Proxy
用于创建对应接口的代理类。具体代理的是哪个委托类,是由实现InvocationHandler
接口的中介类决定的Java自带的动态代理具体实现:
1.创建抽象主题 —— 与静态代理类一致,不再展示
2.创建实现类 —— 与静态代理类一致,不再展示
3.实现InvocationHandler
接口,创建中介类
public class AnimalInvokeHandler implements InvocationHandler {
private Animal animal;
public AnimalInvokeHandler(Animal animal) {
this.animal = animal;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy class: " + proxy.getClass().getName());
System.out.printf("proxy instanceof Animal: %b \n", proxy instanceof Animal);
System.out.printf("---- Call method: %s, class: %s ----\n", method.getName(), animal.getClass().getSimpleName());
// 通过反射,调用委托类的方法
Object result = method.invoke(animal, args);
return result;
}
}
4.通过Proxy
创建动态代理类,实现对抽象主题的代理
public static void main(String[] args) {
// 通过Proxy.newProxyInstance创建代理类
// 将代理类转为抽象主题,可以动态的创建实现了该主题的代理类
// 必须从实现类去获取需要代理的接口
// 指定中介类,通过中介类实现代理
Animal proxy = (Animal) Proxy.newProxyInstance(Main.class.getClassLoader(), Dog.class.getInterfaces(), new AnimalInvokeHandler(new Dog()));
proxy.eat();
}
执行结果:
Java原生的动态代理,利用反射动态生成代理类字节码ProxyX.class
,然后将其强制转化为抽象主题类型,就能实现对该接口的代理
jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口
Java原生动态代理,又叫jdk动态代理,具有以下优缺点
1.优点: jdk动态代理,避免了静态代理需要创建并维护过多的代理类的
2.缺点: jdk动态代理只能代理接口,因为Java的单继承原则:代理类本身已经继承了Proxy
类,就不能再继承其他类,只能实现委托类的抽象主题接口。
一个类中有两个方法methodA
:转账到其他账户,methodB
:查询账户余额。
如果用户访问methodA
,希望先提示用户检查账户信息是否正确;
如果用户访问methodB
,希望在用户查询完余额后,提示用户关注银行的微信公众号。
cglib
实现对类的动态代理 —— 小白看了实现后,可能会倾向于说这就是类似JAVA WEB的拦截器 😂添加Maven依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.11</version>
</dependency>
简化版的银行系统类
public class BankSystem {
// 转账
public boolean transferAccount(double amount, String address) {
System.out.printf("Send %f dollars to account %s", amount, address);
// 转账成功
return true;
}
// 查询账户余额
public String queryBalance(){
System.out.printf("Query account balance success");
return "Account balance: 2400 dollars";
}
}
为转账方法创建拦截器
public class TransferInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before(objects);
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
private void before(Object[] args){
System.out.printf("Please check: you will send %.2f dollar to account %s.\n", args[0], args[1]);
}
}
为余额查询方法创建拦截器
public class QueryBalanceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 调用预发插叙方法
Object result = proxy.invokeSuper(obj, args);
after();
return result;
}
private void after() {
System.out.printf("Please pay attention to WeChat official account.\n");
}
}
创建filter,实现方法与拦截器的映射
public class BankFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if ("transferAccount".equals(method.getName())) {
// 使用拦截器列表中的第1个拦截器
return 0;
}
// 使用拦截器列表中的第2个拦截器
return 1;
}
}
使用cglib实现动态代理 —— 我认为就是方法拦截 😂
public static void main(String[] args) {
// 新建拦截器
TransferInterceptor transferInterceptor = new TransferInterceptor();
QueryBalanceInterceptor queryBalanceInterceptor = new QueryBalanceInterceptor();
// 创建工具类
Enhancer enhancer = new Enhancer();
// 设置委托类,在cglib中,这是cglib需要继承的超类
enhancer.setSuperclass(BankSystem.class);
// 设置多个拦截器
enhancer.setCallbacks(new Callback[]{transferInterceptor, queryBalanceInterceptor});
// 实现拦截器和方法的映射,即为不同的方法配置不同的拦截器
enhancer.setCallbackFilter(new BankFilter());
// 创建代理类
BankSystem proxy = (BankSystem) enhancer.create();
// 执行转账,调用TransferInterceptor
boolean ok = proxy.transferAccount(1024.28, "lucy");
System.out.println("transfer money success: " + ok);
// 查询余额,调用QueryBalanceInterceptor
proxy.queryBalance();
}
cglib总结:
1.优点1: cglib基于类实现动态代理,通过ASM字节码框架动态生成委托类的子类,并使用方法拦截器实现对委托类方法的拦截。
2.优点2: 基于ASM字节码框架动态生成代理类,比jdk动态生成代理类更加高效
3.缺点: 通过继承委托类创建动态代理类,因此不能代理final委托类或委托类中的final方法。
java中代理的实现
共有三种方法:静态代理、JDK动态代理、cglib动态代理
Proxy.newProxyInstance()
为抽象主题创建代理类,被代理的委托类包含在InvocationHandler
类中,由InvocationHandler
类的invoke
方法通过反射实现对委托类方法的调用三种代理方式的比较
1.静态代理,需要创建并维护大量的委托类
2.jdk动态代理,避免了静态类的上述缺点,但只能代理接口(Java单继承原则,代理类已经继承了Proxy
类)
3.cglib动态代理,可以实现对类的代理,并通过方法拦截器实现对委托类(父类)方法的拦截;使用强大的ASM字节码框架,更加高效;通过继承实现对类的代理,使其无法代理final类或类中的final方法
为何调用代理类的方法,会自动进入InvocationHandler
的invoke()
方法?
newProxyInstance()
创建代理类时,会为代理类设置InvocationHandler
:h
h.invoke()
方法
this.h.invoke(this, method, args);
因此,调用代理类的方法时,实际上会调用InvocationHandler
的invoke()
方法
到此这篇关于浅谈Java动态代理的实现的文章就介绍到这了,更多相关Java动态代理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 浅谈Java动态代理的实现
本文链接: https://lsjlt.com/news/126751.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0