AOP:面向切面编程,将某段代码动态切入到指定方法的指定位置进行运行的这种编程方式。
1、动态代理–Proxy的使用
这里以加减乘除为例子。
创建加减乘除的方法接口:Calculator.java
package com.msb.service;
public interface Calculator {
public Integer add(Integer i,Integer j) throws NoSuchMethodException;
public Integer sub(Integer i,Integer j) throws NoSuchMethodException;
public Integer mul(Integer i,Integer j) throws NoSuchMethodException;
public Integer div(Integer i,Integer j) throws NoSuchMethodException;
}
创建继承接口的方法具体实现类:MyCalculator.java
package com.msb.service;
import com.msb.util.LogUtil;
import org.omg.PortableInterceptor.INACTIVE;
import java.lang.reflect.Method;
public class MyCalculcator implements Calculator {
public Integer add(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i+j;
return result;
}
public Integer sub(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i-j;
return result;
}
public Integer mul(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i*j;
return result;
}
public Integer div(Integer i, Integer j) throws NoSuchMethodException {
Integer result = i/j;
return result;
}
}
创建动态代理类:CalculcatorProxy.java
package com.msb.proxy;
import com.msb.service.Calculator;
import com.msb.util.LogUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 必须要有接口,若没有接口不能使用,这种方式使用的是jdk的reflect下的类
* 若无接口,可以使用cglib
* Spring中使用了两种动态代理,Proxy、cglib
*/
public class CalculcatorProxy {
public static Calculator getCalculcator(final Calculator calculator){ //匿名类里边无法调用外部函数的值
ClassLoader loader = calculator.getClass().getClassLoader(); //类装载器
Class[] interfaces = calculator.getClass().getInterfaces(); //获取所有接口
//用来执行被代理类需要执行的方法
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //代理对象、代理方法、方法参数
Object result = null;
try{
LogUtil.start(method,args);
//invoke:开始调用被代理类的方法
result = method.invoke(calculator,args);
LogUtil.stop(method,result);
}catch (Exception e){
LogUtil.logException(method,e);
e.printStackTrace();
}finally {
LogUtil.logFinally(method);
}
return result;
}
};
Object o = Proxy.newProxyInstance(loader, interfaces, handler); //动态代理
return (Calculator) o;
}
}
动态代理主要使用的是Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法。
方法中的参数:
(1)ClassLoader loader:类的装载器,可以通过类名.getClass().getClassLoader得到;
(2)Class<?>[] interfaces:interface是接口,interfaces便是全部接口,这里获取的应该是代理类的全部接口;
(3)InvocationHandler h:定义这个类的对象后发现还有需具体实现的方法invoke():执行代理类需要执行的方法
测试类:MyTest.java
import com.msb.proxy.CalculcatorProxy;
import com.msb.service.Calculator;
import com.msb.service.MyCalculcator;
import org.junit.Test;
public class MyTest {
//这里使用的是junit
@Test
public void test01() throws NoSuchMethodException {
Calculator calculcator = CalculcatorProxy.getCalculcator(new MyCalculcator());
calculcator.add(1,2);
System.out.println(calculcator.getClass());
}
}
总结:这里使用的其实是jdk提供的动态代理类,Spring中是通过注解来实现,但是底层依赖的还是动态代理。
这个案例其实就是想说,若不使用动态代理,在每个方法中都需要 添加相同的代码块,使用动态代理其实就是将这部分代码封装成一个类,然后通过动态代理中调用这个类中的方法,还有实现代码逻辑的操作方法,也就是其他功能都是通过代码模块化实现,最终使用动态代理Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)去实现,而 方法前面两个参数都可以直接获取,主要是第三个参数,第三个参数中可以写入需要代理的方法。