因为学习spring框架时涉及到了AOP 面向切面编程,并且使用到了动态代理的知识,所以来写一篇博客纪录下,动态代理相关知识和aop的一些简单知识
首先我们来看下
AOP(面向切面编程) :通俗的说,就是在不动源码的基础上对代码进行增强!通过增强我们可以干好多事,比如修改编码之类的!
那么不对源码进行修改就进行增强的方式,我想到了 三种方法
1.继承
2.装饰者模式
3.动态代理
我们来看下动态代理
首先动态代理就是在不修改原代码基础上,对代码进行增强
目前我知道的动态代理有两类
- 基于接口的动态代理 由jdk 提供
- 基于子类的动态代理 由cglib提供(spring框架就使用这种,因为你没办法要求每个类都实现了接口,但是只要类不是被final修饰的,就可以继承!)
我们首先来看下基于接口的动态代理
首先我们需要一个代理类,java规定这个类必须实现 InvocationHandler 接口,然后通过该接口的 Invoke 方法来对代码进行增强
我现在要实现的就是 卖水果的人在处理水果的时候,偷偷吃掉了水果,既然是偷偷的,那我就不能告诉顾客!所以我们来增强下
首先我们需要一个代理类,下面上代码!
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import interfaces.FruitInterface;
public class MyProxy implements InvocationHandler {
//这里是你一会要增强的那个方法的类,通过下面的构造函数赋值
private FruitInterface fruit;
public MyProxy() {
super();
}
public MyProxy(FruitInterface fruit){
this.fruit = fruit;
}
/**
*下面这个方法就是用来增强代码的,每个被代理类的方法执行前都会经过下面这个方法
*@param 第一个参数 是代理对象的引用
*@param 第二个参数 是当前正在执行的方法
*@param 第三个参数 是当前执行方法的参数
**/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy is starting");
if("deal".equals(method.getName())){
System.out.println("处理的时候就偷偷吃掉了!");
}
Object invoke = method.invoke(fruit, args);//这里就是用了反射来执行方法
System.out.println("proxy is ending");
return invoke;
}
}
既然代理的类有了,我们需要有被代理类,也就是谁要被增强!因为我们是基于接口的的动态代理,所以先建一个简单的接口
public interface FruitInterface {
public void deal();
public void end();
}
然后再实现该接口
import interfaces.FruitInterface;
public class FruitImpl implements FruitInterface {
@Override
public void deal() {
System.out.println("fruit is dealing");
}
@Override
public void end() {
System.out.println("fruit is end!!");
}
}
然后我们就可以开始增强了
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import interfaces.FruitInterface;
import interfaces.impl.FruitImpl;
import proxy.MyProxy;
public class EatFruit {
public static void main(String[] args) {
FruitInterface fruit = new FruitImpl();
//获得代理类的handle
MyProxy handle = new MyProxy(fruit);
//调用Proxy的newProxyInstance方法获取一个经过增强的对象
FruitInterface as = (FruitInterface)Proxy.newProxyInstance(fruit.getClass().getClassLoader(), fruit.getClass().getInterfaces(), handle);
//然后接下来调用已经增强好的对象的方法,你会发现你已经开始偷吃水果了
//这个过程我们并没有去修改Fruit类的代码而实现了这一目的
as.deal();
as.end();
}
}
那我们再来看一看 基于子类的动态代理,因为是cglib提供的 ,所以我们需要引入jar包
asm-3.1.wso2v1.jar
cglib-2.2.jar
下载地址
https://download.csdn.net/download/u013781343/10552203
这个动态代理我并没有修改什么代码,只是在原来的EatFruit 类中做了相应的变化,下面上代码,具体说明都在注释里
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import interfaces.FruitInterface;
import interfaces.impl.FruitImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import proxy.MyProxy;
public class EatFruit {
public static void main(String[] args) {
FruitInterface fruit = new FruitImpl();
//cglib实现动态代理
/**这里用到了Enhancer类的create方法
**第一个参数是被代理类的字节码 第二个参数是如何代理,类似于InvocationHandle接口
**不过我们这里使用的是MethodInterceptor()这个子接口
**需要我们使用里面的intercept方法来进行方法增强
**/
FruitInterface create = (FruitInterface)Enhancer.create(FruitImpl.class, new MethodInterceptor() {
//执行被代理对象的任何方法都会执行该方法,用法和刚才的 jdk的动态代理一样
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理开始!");
if("deal".equals(method.getName())){
System.out.println("我又开始偷吃了!");
}
method.invoke(fruit, args);
return null;
}
});
create.deal();
create.end();
}
}
这样最终结果是
这就是两种动态代理方式,接下里就可以研究一下 AOP 里面的 切入点,通知等知识点了