我们来定义一下 AOP(面向切面编程)
它是面向对象的一种补充或者是一种增强,它在这基础上增加了一些
而外的功能增强。
它可以在原有的行为不改变的前提,在这之前或者之后完成一些而外
的事情。
而AOP用的思想和模式就是代理模式。
代理模式分为两种:
1.静态代理。
静态代理的代理类是开发人员自行编写的,并且在编译期就已经
确定。编写相应的接口和实现类,同时编写一个代理类实现这个接口。
缺点:
1.需要为每一个目标对象编写相应得代理实例,从而代理不同的业
务逻辑。
2.当接口发生变动时,所有的代理类和实现了都必须修改。
举个小例子:
Interface:Computer
package org.proxy; /** * Created by Administrator on 2016/11/25. */ //编写一个接口 public interface Computer { public void sell( int money ); }
Class:LenovoComputer
package org.proxy; /** * Created by Administrator on 2016/11/25. */ //编写一个类,继承Computer接口 public class LenovoComputer implements Computer { //重写其方法 @Override public void sell( int money ) { System.out.println( "实收金额" + money ); } }
Proxy:LenovoProxy
package org.proxy; /** * Created by Administrator on 2016/11/25. * 编写一个代理对象 */ public class LenovoProxy implements Computer { //定义要代理的对象 private LenovoComputer lenovo; //在构造方法中传入LenovoComputer参数 public LenovoProxy( LenovoComputer lenovo ) { this.lenovo = lenovo; } @Override public void sell(int money) { //在将成本交给厂家之前,先扣去利润 money = money - 500; System.out.println( "代理商赚取了500" ); //调用方法 lenovo.sell( money ); } }
Main方法:
package org.proxy; /** * Created by Administrator on 2016/11/25. */ public class User { //main方法 public static void main(String[] args) { //实例化代理对象,代理LenovoComputer,调用其方法 Computer c = new LenovoProxy( new LenovoComputer() ); System.out.println( "用户付款了3000元" ); //调用其方法 c.sell( 3000 ); } }
运行结果为:
2.动态代理。
使用动态代理,代理实例时不需要开发人员去编写的,而是由相应
的处理程序在运行时动态产生一个字节码,这个字节码就是代理对象,加
载到JVM中。由于代理实例时在运行时才会动态产生,因此就叫做动态代理。
它和静态代理的区别就在于,静态代理的实例时人为编写的,并且编译器就
已经确定的。
在Java语言层面实现动态代理的机制有很多,我们只举JDK动态代理。
JDK动态代理(官方):
1.Proxy类,用于动态产生代理对象。
2.InvocationHandler接口,回调处理器,负责调用目标对象的行为,并实现
功能增强。
JDK动态代理有一个特点,就是被代理的对象必须要有接口,如果没有接口,是实现不了
代理的。
举个例子:
Work接口:
package org2.proxy; /** * Created by Administrator on 2016/11/25. * 编写一个接口 */ public interface Work { //接口中的抽象方法 public void work(); }
Teacher类实现Work接口:
package org2.proxy; /** * Created by Administrator on 2016/11/25. * 编写一个类实现该接口 */ public class Teacher implements Work { //重写方法 @Override public void work() { System.out.println( "老师上课了" ); } }
回调处理器:
package org2.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Created by Administrator on 2016/11/25. * 编写一个回调处理器 * 用于实现功能的增强,和调用目标对象的行为 */ public class WorkInvocationHandler implements InvocationHandler { //这个对象就是被代理的对象 private Object target; //将被代理对象传入构造方法中 public WorkInvocationHandler( Object target ) { this.target = target; } //这个方法就是核心的回调方法 //它可以用来调用被代理对象的具体行为 //同时在调用目标对象方法之前或者之后做一些事情 //从而实现功能的增强 //参数一:代理对象,JDK运行时动态产生 //参数二:被代理对象需要执行的方法 //参数三:被代理对象执行的方法所需的参数 @Override public Object invoke(Object proxy, Method method, Object[] args ) throws InvocationTargetException, IllegalAccessException { //在调用目标对象行为之前做一些事情 System.out.println( "before:上课点名" ); //回调目标对象的具体行为 //回调方法之后一样有返回值, //这个返回值就是目标对象的返回值 Object returnVal = method.invoke( target, args ); //在调用目标对象行为之后做一些事情 System.out.println( "after:布置作业" ); return returnVal; } }
Main方法:
package org2.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * Created by Administrator on 2016/11/25. * main方法 */ public class Main { public static void main(String[] args) { //创建需要被代理的对象 Teacher teacher = new Teacher(); //创建一个回调处理器,回调处理器会去调用teacher中的方法 InvocationHandler handler = new WorkInvocationHandler( teacher ); //使用Proxy类在运行时动态创建一个代理对象 //上面定义的回调处理器需要传递给这个Proxy类生成代理对象 //参数一:类加载器 //参数二:目标对象所实现的所有接口 //(由于JDK动态代理是基于接口来产生代理对象的,也就是创建出来的代理对象必须要实现一个接口) //参数三:回调处理器 //newProxyInstance方法的返回值就是一个创建好的代理实例 Work work = ( Work )Proxy.newProxyInstance( Teacher.class.getClassLoader(), teacher.getClass().getInterfaces(), handler ); //调用其方法 work.work(); } }
运行结果:
---------------------------------------------------------