为什么要用动态代理?
•代码混乱:越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀. 每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点.
•代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码. 如果日志需求发生变化, 必须修改所有模块.
问题:
普通代码:
ArithmeticCalculator接口
package com.yorkmass.spring.aop.helloworld;
public interface ArithmeticCalculator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i,int j);
int div(int i,int j);
}
ArithmeticCalculatorLoggingImpl类
package com.yorkmass.spring.aop.helloworld;
public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
System.out.println("The method add begins with["+i+","+j+"]");
int result=i+j;
System.out.println("The method add ends with"+result);
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("The method sub begins with["+i+","+j+"]");
int result=i-j;
System.out.println("The method sub ends with"+result);
return result;
}
@Override
public int mul(int i, int j) {
System.out.println("The method mul begins with["+i+","+j+"]");
int result=i*j;
System.out.println("The method mul ends with"+result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("The method div begins with["+i+","+j+"]");
int result=i/j;
System.out.println("The method div ends with"+result);
return result;
}
}
然后自己写测试类运行即可
但是上面如果后期有需求需要对代码进行修改,则需要对每一行的日志文件进行修改,特别不方便修改。
我们能不能去掉每个方法的输入语句,只写一个,来实现对所有方法的日志管理,这样修改起来也比较方便,
动态代理便可以很好的解决这个问题。
使用动态代理解决问题
•代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.
动态代理解决办法:
我们把 ArithmeticCalculatorImpl类写的尽可能简单
ArithmeticCalculatorImpl类
package com.yorkmass.spring.aop.helloworld;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result=i+j;
return result;
}
@Override
public int sub(int i, int j) {
int result=i-j;
return result;
}
@Override
public int mul(int i, int j) {
int result=i*j;
return result;
}
@Override
public int div(int i, int j) {
int result=i/j;
return result;
}
}
我们开始配置动态代理
ArithmeticCalculatorLoggingProxy类
package com.yorkmass.spring.aop.helloworld;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import javax.naming.spi.DirStateFactory.Result;
import org.omg.CORBA.PUBLIC_MEMBER;
public class ArithmeticCalculatorLoggingProxy {
//要代理的对象
private ArithmeticCalculator targer;
public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
// TODO Auto-generated constructor stub
this.targer=target;
}
public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy=null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader=targer.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces=new Class[]{ArithmeticCalculator.class};
//当调用代理对象其中的方法时,该执行的代码
InvocationHandler h=new InvocationHandler() {
/**
* proxy:正在返回的那个代理对象,一般情况下,在invoke方法中都不适用该对象。
* method:正在调用的方法
* args:调用方法时,传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName=method.getName();
//日志
System.out.println("The method..."+methodName+"begins with"+Arrays.asList(args));
//执行方法
Object result=method.invoke(targer, args);
//日志
System.out.println("The method"+methodName+"ends with "+result);
return result;
}
};
proxy=(ArithmeticCalculator)Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
测试主类Main:
package com.yorkmass.spring.aop.helloworld;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
// ArithmeticCalculator arithmeticCalculator=null;
// arithmeticCalculator=new ArithmeticCalculatorLoggingImpl();
ArithmeticCalculator target=new ArithmeticCalculatorImpl();
ArithmeticCalculator proxy=new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();
int result=proxy.add(1, 2);
System.out.println("-->"+result);
result=proxy.div(4, 2);
System.out.println("-->"+result);
}
}
运行结果:
The method...addbegins with[1, 2]
The methodaddends with 3
-->3
The method...divbegins with[4, 2]
The methoddivends with 2
-->2
动态代理可以实现模块化编程 !
Spring AOP可以更好的解决这个问题,有兴趣请看博主spring AOP文章:https://blog.csdn.net/qq_36949176/article/details/86537951