Spring框架有个核心思想,AOP:面向切面编程,使用AOP可以实现核心业务与辅助业务的分离,同时也可以在执行核心业务时,将一些辅助的业务加进来,比如日志,权限控制等。那么SpringAOP实现原理是什么呢?动态代理。其实动态代理是一种比较重要设计模式。那么如何去实现动态代理呢。其实有两种方式:JDK、CGLIB。(这两句话也是常见的面试问题)今天就介绍一下动态代理以及如何使用JDK实现动态代理。
举个简单的例子:比如,我现在饿了,想吃饭,那么我就需要先买菜、然后做饭,然后吃饭、吃完呢,还需要收拾桌子、刷盘子。我在家呢,比较懒,不想动,但又饿想吃饭。怎么办呢。可能就会求老妈,去买菜,然后做饭,然后我就吃饭,吃完呢,老妈又去收拾桌子、刷盘子(老妈辛苦了。。)其实这里就运用到了代理思想,老妈就是一个代理对象。我的核心业务就是吃饭,其他非核心业务就交给代理对象(老妈)去做。
package service;
public interface People {
void eat();
}
class Me implements People{
@Override
public void eat() {
System.out.println("买菜中。。。。。");
System.out.println("做饭中。。。。。");
System.out.println("吃饭中。。。。。");
System.out.println("收拾桌子。。。。");
System.out.println("刷盘子。。。。。");
}
}
非代理模式下:核心业务与辅助业务写在了一个方法中,除了业务冗余 代码的耦合度也高,同时复用还低
package service;
interface People {
void eat();
}
class MeProxyMother implements People{
private People me;
public MeProxyMother(People me) {
super();
this.me = me;
}
public void prepareFood(){
System.out.println("mother买菜中。。。。。");
System.out.println("mother做饭中。。。。。");
}
public void clean(){
System.out.println("mother收拾桌子。。。。");
System.out.println("mother刷盘子。。。。。");
}
@Override
public void eat() {
this.prepareFood();
me.eat();
this.clean();
}
}
class Me implements People{
@Override
public void eat() {
System.out.println("Me吃饭中。。。。。");
}
}
public class TestProxy{
public static void main(String[] args){
People people = new MeProxyMother(new Me());
people.eat();
}
}
通过使用代理的思想修改后,可以清楚的发现,通过代理模式,我们可以抽取出核心业务与辅助业务,业务层代码很纯很纯,就是一个吃,其他非核心代码是由代理类去实现的。但也发现一个问题我们写的代理类MeProxyMonther只能服务于People这个接口。如果我一万个接口需要使用代理。那岂不是要写一万个代理类。其实我们上面只是代理模式的一种类型叫静态代理。缺点很明显,静态代理只能服务于一种类型的对象,不利于业务的扩展,想能不能写一个代理类,去服务所有的接口。那么这就是今天的主角动态代理。
实现动态代理有两种方式:JDK和Cglib 我们这里使用JDK来实现动态代理;我们编写这个代理类需要实现一个InvocationHandle接口。包路径java.lang.reflect.InvocationHandler。它其实是通过反射的形式来实现的。该接口中有一个需要实现的方法:
Ojbect proxy:表示需要代理的对象
Method method:表示要操作的方法
Object[] args:method方法所需要传入的参数(可能没有为,null.也可能有多个)
Object invoke(Object proxy, Method method, Object[] args)
//代理类实际调用的方法并返回处理结果。
同时,我们还需要一个实例化代理对象的方法,这时我们需要用到另外一个类。java.lang.reflect.Proxy Proxy
提供用于创建动态代理类和实例的静态方法,它还是这些方法创建的所有动态代理类的超类。该类里有个静态方法:
param:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
return:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口。
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
package service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ServiceProxy implements InvocationHandler {
private Object target = null;
public Object getProxy(Object target){
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("做饭ing"); // Spring的前置通知
Object result = method.invoke(target, args);
System.out.println("刷碗ing"); // Spring的后置通知
return result;
}
public static void main(String[] args){
PeopleService peopleServiceImpl = (PeopleService)new ServiceProxy().getProxy(new PeopleServiceImpl());
peopleServiceImpl.eat("Me", "鱼香肉丝");
}
}
interface PeopleService{
void eat(String name,String food);
}
class PeopleServiceImpl implements PeopleService{
@Override
public void eat(String name, String food) {
System.out.println("name"+"正在吃"+food);
}
}
动态代理和静态代理相比较,最大的好处就是接口中声明的所有的方法都被转移到一个集中的方法中去处理,就是invocke()方法,不需要一个一个的去写代理类。动态代理只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的。
注意:JDK和CGLIB实现动态代理的区别?
(1)JDK动态代理只能对实现了接口invocationHandler的类
生成代理。原理主要是利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类
(2)CGLIB不需要实现接口。原理主要是利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。以该类或方法不要声明成final
package service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ServiceLogProxy implements InvocationHandler {
private Object target;
public Object getProxy(Object target){
this.target =target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
private Long before(Method method){
// 可以自定义实现更复杂的业务逻辑,这部分书写的逻辑,就相当于Spring的前置通知
System.out.println(target.getClass().getName()+"."+method.getName()+"()");
long currentTimeMillis = System.currentTimeMillis();
return currentTimeMillis;
}
private void after(Long startTime ,Method method){
// 可以自定义实现更复杂的业务逻辑,这部分书写的逻辑,就相当于Spring的后置通知
System.out.println(target.getClass().getName()+"."+method.getName()+"()"+"success!"+"time:"+String.valueOf(System.currentTimeMillis()-startTime)+"ms");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Long startTime = this.before(method);
Object result = method.invoke(target, args);
this.after(startTime, method);
return result;
}
public static void main(String [] args){
PeopleService peopleService = (PeopleService)new ServiceLogProxy().getProxy(new PeopleServiceImpl());
peopleService.eat("zjh", "fish");
People people = (People)new ServiceLogProxy().getProxy(new Me());
people.eat();
}
}