Spring4.0学习笔记007——AOP基础:动态代理概念解析
Posted yfyzwr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring4.0学习笔记007——AOP基础:动态代理概念解析相关的知识,希望对你有一定的参考价值。
问题的引出
首先新建名为
SpringAOP
的java工程,为其创建名为com.yfyzwr.spring.aop
的package,在该包中创建名为ArithmeticCalculator
的接口。public interface ArithmeticCalculator int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int dev(int i, int j);
创建名为
ArithmeticCalculatorImpl
的java类,实现上述的ArithmeticCalculator
接口。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 dev(int i, int j) int result = i / j; return result;
现在遇到新的需求:
- 需求1-日志:在程序执行期间追踪正在发生的活动
- 需求2-验证:希望计算器只能处理正数的运算
对于上述的需要,我们首先想到的就是“在每个方法的开始和结尾添加日志和验证的语句”,如下所示。
public int add(int i, int j) System.out.println("add method begin ..."); int result = i + j; System.out.println("add method end ..."); return result;
分析这种实现,不难发现这种处理方式有些不足的地方需要指出:
- 每个方法都这样实现,会增加代码的复杂程度,增加维护成本。
- 一旦需要改变日志的打印内容,那么每个函数都要改动,这很可能就是巨大的工作量。
所以需要能够统一的管理这些日志打印、验证等工作,这就需要借助“动态代理”的模式。
动态代理的实现
新建名为
ArithmeticCalculatorLoggingProxy
的java类。public class ArithmeticCalculatorLoggingProxy //被代理的对象 private ArithmeticCalculator target; public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) this.target = target; public ArithmeticCalculator getLoggingProxy() ArithmeticCalculator proxy = null; //被代理对象由哪一个类加载器来负责加载 ClassLoader loader = target.getClass().getClassLoader(); //被代理对象的类型,即该类型有哪些方法 //Class [] interfaces = new Class[]ArithmeticCalculator.class; Class [] interfaces = target.getClass().getInterfaces(); //当调用代理对象的方法时,需要执行的代码 InvocationHandler h = new InvocationHandler() @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable System.out.println("proxy invoke ..."); return 0; ; proxy = (ArithmeticCalculator)Proxy.newProxyInstance(loader, interfaces, h); return proxy;
特别注意:Proxy.newProxyInstance()的第二个参数是Class类型的数组,而该数组要求的是“接口类型的Class元素。
新建带有main方法的类。
public static void main(String[] args) ArithmeticCalculator target = new ArithmeticCalculatorImpl(); ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy(); int result = proxy.add(1, 2); System.out.println("add result :" + result);
运行程序,查看输出结果。
proxy invoke …
add result :0本来调用add(1, 2)方法应该输出的结果为3,但是现在的输出结果却是Proxy类的实现内容,所有代理操作已经成功。
再修改proxy类的实现,现在才来实现日志打印的功能。
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable //方法调用之前的日志 System.out.println("proxy invoke method " + method.getName() + "begin with" + Arrays.asList(args)); //执行方法 Object result = method.invoke(target, args); //方法调用之后的日志 System.out.println("proxy invoke method " + method.getName() + "end with" + result); return result;
运行程序,查看输出结果
proxy invoke method addbegin with[1, 2]
proxy invoke method addend with3
add result :3
特别注意:在开发的时候,可以按上述的方式直接使用动态代理来实现需要的功能,但是却并不建议这样直接使用动态代理。其实完全可以使用更简单的方式来实现,那就是Spring提供的AOP技术。
基础概念的解析
AOP(Aspect-Oriented Programming 面向切面编程):是一种新的方法论,它的主要编程对象是切面(aspect),而切面模块化横切关注点。
从上述的演进过程,可以得知AOP的好处大致为:
- 每个事物逻辑(如日志、验证等)位于一个位置,代码不分散,便于维护和升级。
- 业务模块更简洁,只需关注于核心业务代码。
先来看看上述程序示例的AOP分析图,帮助我们理解相关的概念。
- 切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象。
- 通知(Advice):切面必须要完成的工作。
- 目标(Target):被通知的对象。
- 连接点(Joinpoint):程序执行到的某个特定位置(如类某个方法调用前、调用后、方法抛出异常后等)。每个类都拥有多个连接点(如 ArithmethicCalculator 的所有方法实际上都是连接点),即连接点是程序类中客观存在的事务。
以上是关于Spring4.0学习笔记007——AOP基础:动态代理概念解析的主要内容,如果未能解决你的问题,请参考以下文章
Spring4.0学习笔记008——AOP的配置(基于注解)
Spring4.0学习笔记008——AOP的配置(基于注解)
Spring4.0学习笔记009——AOP的配置(基于XML文件)