写一个计算类,计算前后需要打印日志。

interface ArithmeticCalculator {
public int add(int i, int j);
public int sub(int i, int j);
public int mul(int i, int j);
public int div(int i, int j);
}
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

    @Override
public int add(int i, int j) {
// TODO Auto-generated method stub
System.out.println("The method add begins with[" + i + "," + j + "]");
int result = i + j;
System.out.println("The method add ends with " + result);
return result;
} @Override
public int sub(int i, int j) {
// TODO Auto-generated method stub
System.out.println("The method sub begins with[" + i + "," + j + "]");
int result = i - j;
System.out.println("The method sub ends with " + result);
return result;
} @Override
public int mul(int i, int j) {
// TODO Auto-generated method stub
System.out.println("The method mul begins with[" + i + "," + j + "]");
int result = i * j;
System.out.println("The method mul ends with " + result);
return result;
} @Override
public int div(int i, int j) {
// TODO Auto-generated method stub
System.out.println("The method div begins with[" + i + "," + j + "]");
int result = i / j;
System.out.println("The method div ends with " + result);
return result;
} }

从上面代码可以看出,四个方法的日志有重复的部分。

Main.java

public class Main {

    public static void main(String[] args) {
// TODO Auto-generated method stub
ArithmeticCalculator arithmeticCalculator = null;
arithmeticCalculator = new ArithmeticCalculatorImpl(); int result = arithmeticCalculator.add(1, 2);
System.out.println("-->" + result); result = arithmeticCalculator.div(4, 2);
System.out.println("-->" + result);
} }

打印结果:

The method add begins with[1,2]
The method add ends with 3
-->3
The method div begins with[4,2]
The method div ends with 2
-->2

结果没什么问题,可是在加入日志后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还要兼顾其他多个关注点,并且在日志需求发生变化时,必须修改所有模块。

接下来,我们使用动态代理解决上述问题

代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象,任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

    @Override
public int add(int i, int j) {
// TODO Auto-generated method stub
int result = i + j;
return result;
} @Override
public int sub(int i, int j) {
// TODO Auto-generated method stub
int result = i - j;
return result;
} @Override
public int mul(int i, int j) {
// TODO Auto-generated method stub
int result = i * j;
return result;
} @Override
public int div(int i, int j) {
// TODO Auto-generated method stub
int result = i / j;
return result;
} }
public class ArithmeticCalculatorLoggingProxy {

    private ArithmeticCalculator target;

    public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
super();
this.target = target;
} public ArithmeticCalculator getLoggingProxy() {
ArithmeticCalculator proxy = null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class [] interfaces = new Class[]{ArithmeticCalculator.class};
//当调用代理对象其中的方法时,该执行的代码
InvocationHandler h = new InvocationHandler() {
/**
* proxy: 正在返回的那个代理对象,一般情况下,在invoke方法中都不使用对象
* method: 正在被调用的方法
* args: 调用方法时,传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
String methodName = method.getName();
//日志
System.out.println("The methods " + methodName + " begins with" + Arrays.asList(args));
//执行方法
Object result = method.invoke(target, args);
//日志
System.out.println("The methods " + methodName + " ends with" + result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}

Main.java

     ArithmeticCalculator target = new ArithmeticCalculatorImpl();
ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy(); int result = proxy.add(1, 2);
System.out.println("-->" + result); result = proxy.div(4, 2);
System.out.println("-->" + result);

打印结果:

The methods add begins with[1, 2]
The methods add ends with3
-->3
The methods div begins with[4, 2]
The methods div ends with2
-->2

用了动态代理方法,就会发现ArithmeticCalculatorImpl实现类变得清洁很多。并且日志被封装在invoke方法中,修改十分方便。

aop术语:

切面:横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象

通知:切面必须要完成的工作

目标:被通知的对象

代理:向目标对象应用通知之后创建的对象

连接点:程序执行的某个特定位置,如类某个方法调用前,调用后,方法抛出异常后

由两个信息确定:方法表示的程序执行点,想对点表示的方位。

切点:每个类都拥有多个连接点,即连接点是程序类中客观存在的事务。

AOP通过切点定位到特定的连接点:类比:连接点相当于数据库中的记录,切点相当于查询条件。

前置通知:

Spring-aop(一)的更多相关文章

  1. 学习AOP之深入一点Spring Aop

    上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...

  2. 学习AOP之认识一下Spring AOP

    心碎之事 要说知道AOP这个词倒是很久很久以前了,但是直到今天我也不敢说非常的理解它,其中的各种概念即抽象又太拗口. 在几次面试中都被问及AOP,但是真的没有答上来,或者都在面上,这给面试官的感觉就是 ...

  3. spring aop

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将 ...

  4. spring aop注解方式与xml方式配置

    注解方式 applicationContext.xml 加入下面配置 <!--Spring Aop 启用自动代理注解 --> <aop:aspectj-autoproxy proxy ...

  5. 基于Spring AOP的JDK动态代理和CGLIB代理

    一.AOP的概念  在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的 ...

  6. Spring AOP详解

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  7. Spring AOP实例——异常处理和记录程序执行时间

    实例简介: 这个实例主要用于在一个系统的所有方法执行过程中出线异常时,把异常信息都记录下来,另外记录每个方法的执行时间. 用两个业务逻辑来说明上述功能,这两个业务逻辑首先使用Spring AOP的自动 ...

  8. 从零开始学 Java - Spring AOP 实现用户权限验证

    每个项目都会有权限管理系统 无论你是一个简单的企业站,还是一个复杂到爆的平台级项目,都会涉及到用户登录.权限管理这些必不可少的业务逻辑.有人说,企业站需要什么权限管理阿?那行吧,你那可能叫静态页面,就 ...

  9. 从零开始学 Java - Spring AOP 实现主从读写分离

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  10. 从零开始学 Java - Spring AOP 拦截器的基本实现

    一个程序猿在梦中解决的 Bug 没有人是不做梦的,在所有梦的排行中,白日梦最令人伤感.不知道身为程序猿的大家,有没有睡了一觉,然后在梦中把睡之前代码中怎么也搞不定的 Bug 给解决的经历?反正我是有过 ...

随机推荐

  1. Jmeter代理服务器录制请求

    1.文档前提说明 1)本文使用jmeter的版本为 apache-jmeter-2.13 及以上版本 2)java版本要求在 1.8.0 以上 注:jmeter版本一般和java相应的版本一起使用,如 ...

  2. MAC Safari上网弹窗弹广告的最新有效解决方法

    7.3更新: 之前更改DNS好了一段时间,最近在打开其它网页时还是会弹广告: 最终解决方法: 安装MALWAREBYTES 3清理一下: 网址:Free Cyber Security & An ...

  3. Web Assembly背景

    Javascript ,也叫Ecma script,  是这家伙用了 10 天时间赶出来的.. 所以,各位程序猿们,如果你觉得老板 10 天要你们上线一个 App 是一个丧心病狂的事情,那么可以多想想 ...

  4. BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP

    BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP Description 农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏. 初始时,一个有N(5 ...

  5. 「NOIP2014」「LuoguP2296」 寻找道路

    Description 在有向图 G 中,每条边的长度均为 1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 路径上的所有点的出边所指向的点都直接或间接与终点连通. 在 ...

  6. 【SCOI 2009】 Windy数

    [题目链接] 点击打开链接 [算法] 数位DP,注意处理前导零的情况 [代码] #include<bits/stdc++.h> using namespace std; #define M ...

  7. 【前端】CentOS 7 系列教程之五: 安装最新版 nginx 并转发 node 服务

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/linux_5.html 进入/usr/local目录 cd /usr/local 下载最新版的ngxin压缩包 w ...

  8. c/c++内存机制(一)(原)

    一:C语言中的内存机制 在C语言中,内存主要分为如下5个存储区: (1)栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效. (2)堆(Heap):由程 ...

  9. java服务器端断点续传

    Servlet Java代码 复制代码 收藏代码 import java.io.BufferedOutputStream; import java.io.File; import java.io.IO ...

  10. 在头文件#pragma comment(lib,"glaux.lib");编译器提示waring C4081: 应输入“newline“

    在头文件#pragma comment(lib,"glaux.lib");编译器提示waring C4081: 应输入“newline“ #行不能加分号的