Java中动态代理
场景
有一个业务功能接口,接口中有两个业务方法,创建对应的实现类。
package com.klaus.service;
public interface MyService {
public void service1();
public void service2();
}
package com.klaus.service;
public class MyServiceImpl implements MyService {
@Override
public void service1() {
System.out.println("业务方法一");
}
@Override
public void service2() {
System.out.println("业务方法二");
}
}
此时业务功能正常
package com.klaus;
import com.klaus.service.MyService;
import com.klaus.service.MyServiceImpl;
public class main {
public static void main(String[] args) {
MyService myService = new MyServiceImpl();
myService.service1(); //业务方法一
myService.service2(); //业务方法二
}
}
新增功能
此时新增要求,在每个业务执行前打印日志,业务执行后进行事务提交。
解决方法
一、源码更改
第一种很简单,直接在原业务方法上更改。这种方式看起来很简单,但却在业务类中出现了大量重复的、与业务无直接关联的冗余代码。
package com.klaus.service;
public class MyServiceImpl implements MyService {
@Override
public void service1() {
System.out.println("日志信息");
System.out.println("业务方法一");
System.out.println("提交事务");
}
@Override
public void service2() {
System.out.println("日志信息");
System.out.println("业务方法二");
System.out.println("提交事务");
}
}
二、代理类
可以新建一个第三方类,在这个类中呢,既有业务对象,又有新增业务。执行业务的时候不直接在 MyServiceImpl 中调用业务方法,而是首先在第三方类中先调用日志方法(因为会多次用到,所以可以新建工具类吧把新增的日志功能、提交事务功能编成方法加进去);然后通过第三方类中的业务对象调用调用业务方法;最后再在第三方类中调用提交事务的方法。这样就可以实现新的功能,并且不在原来的业务代码上进行改动。新建的这个第三方类称作代理类(自己什么都没有,像是一个中介)。具体示例如下
代理类
package com.klaus;
import com.klaus.service.MyServiceImpl;
import com.klaus.util.ServiceTools;
public class Test {
MyServiceImpl service;
public Test(MyServiceImpl service) {
this.service = service;
}
public void service1(){
ServiceTools.log();
service.service1();
ServiceTools.trans();
}
public void service2(){
ServiceTools.log();
service.service2();
ServiceTools.trans();
}
}
测试类
package com.klaus;
import com.klaus.service.MyService;
import com.klaus.service.MyServiceImpl;
public class main {
public static void main(String[] args) {
Test test = new Test(new MyServiceImpl());
test.service1();
//Thu Aug 12 11:45:42 CST 2021
//业务方法一
//提交事务
System.out.println("++++++++++++++++++++");
//++++++++++++++++++++
test.service2();
//Thu Aug 12 11:45:42 CST 2021
//业务方法二
//提交事务
}
}
三、动态代理
上面的代码是我自己手写的,但是在 Java 中,可以基于 JDK 实现动态代理。这里代理类是MyProxy.java,或者说代理对象是 MyProxy 中的 proxy。JDK 中并没由把代理功能全放在一起实现,而是把方法执行的功能呢交给MyInvocationHandler 做的是接收传递来的方法并处理。
主要方法:
-
Proxy.newProxyInstance()。第一个参数 loader 是目标类(要被代理的类)的类加载器。
第二个参数 interfaces 是目标类实现的接口。
第三个参数 h 是代理对象要执行的功能。
前两个参数都是通过反射得到的。通过代理执行方法,会调用 h 中的 invoke() 方法。public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
-
Method.invoke()。第一个参数 obj 是 要执行的方法所在的类。
第二个参数 args 是方法的参数。
public Object invoke(Object obj, Object... args)
就是和反射一模一样的思想。反射的讲述可以参考这里。
MyInvocationHandler.java
package com.klaus.handler;
import com.klaus.util.ServiceTools;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ServiceTools.log();
Object res = method.invoke(target, args);
ServiceTools.trans();
return res;
}
}
MyProxy.java
package com.klaus.proxy;
import com.klaus.handler.MyInvocationHandler;
import com.klaus.service.MyService;
import com.klaus.service.MyServiceImpl;
import java.lang.reflect.Proxy;
public class MyProxy {
public static void main(String[] args) {
MyService service = new MyServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(service);
MyService proxy =(MyService) Proxy.newProxyInstance(service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
handler);
proxy.service1();
//Thu Aug 12 11:57:34 CST 2021
//业务方法一
//提交事务
System.out.println("++++++++++++++++++++++");
//++++++++++++++++++++++
proxy.service2();
//Thu Aug 12 11:57:34 CST 2021
//业务方法二
//提交事务
}
}
最后是我的
本文来自博客园,作者:klaus08,转载请注明原文链接:https://www.cnblogs.com/klaus08/p/15132115.html