AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

  

AOP 的应用范围

  传统的程序通常表现出一些不能自然地适合单一的程序模块或者是几个紧密相关的程序模块的行为,AOP 将这种行为称为横切,它们跨越了给定编程模型中的典型职责界限。横切行为的实现都是分散的,软件设计师会发现这种行为难以用正常的逻辑来思考、实现和更改。最常见的一些横切行为如下面这些:

 

  日志记录,跟踪,优化和监控

 

  事务的处理

 

  持久化

 

  性能的优化

 

  资源池,如数据库连接池的管理

 

  系统统一的认证、权限管理等

 

  应用系统的异常捕捉及处理

 

  针对具体行业应用的横切行为

Spring 为解耦而诞生,其中AOP(面向切面编程)是很浓重的一笔。

这里简单记录一下AOP 给我带来的好处:

1.

用了一段时间,想通过简单的代码,更好的阐述以及理解它。

以前:假设我们有个简单的业务,还是经典的Hello World,那么我们定义一个Service 接口,一个ServiceImpl 实现类,一个sayHello 方法,这里使用网上很经典的日志记录的例子。

1.Service接口:定义一个sayHello  的业务方法

2.ServiceImpl实现类:主要是打印HelloWord,但是日常项目中,在主要业务前后可能会添加日志记录,或者开启事务等其他必要操作。

  1. public class ServiceImpl implements Service{  
    
        @Override
    public void sayHello() {
    System.out.println("前置日记:打印、启动事务等..");
    System.out.println("Hello world!");
    System.out.println("后置日记:打印、关闭事务等..");
    }
    }

例子很简单,那么假设,我们不光拥有sayHello ,还有sayBye 等多个方法,并且都需要其他操作呢?那么你是不是会写很多个这样的,重复的代码?

当然,你可以减少一部分工作量,你可以这样:

  1. public class ServiceImpl implements Service{  
    
        @Override
    public void sayHello() {
    before();
    System.out.println("Hello world!");
    after();
    } @Override
    public void sayBye() {
    before();
    System.out.println("Bye bye!");
    after();
    } public static void before(){
    System.out.println("前置日记:打印、启动事务等..");
    } public static void after(){
    System.out.println("后置日记:打印、关闭事务等..");
    }
    }

我们再次假设,如果我们拥有更多的业务方法:sayHi(),sayOther()....,需要更多的其他操作:打印信息,传输记录....。并且其他ServiceImpl 里面的方法也需要这些方法呢?那么我们是不是每个类又要继续添加呢?

当然,你可以这样做:建立一个对Service 添加额外功能的类,统一提供。

  1. public class ServiceFactory {
    public static void before(){
    System.out.println("前置日记:打印、启动事务等..");
    } public static void after(){
    System.out.println("后置日记:打印、关闭事务等..");
    } public static void other(){
    System.out.println("做其他的事..");
    }
    }

ServiceImpl 就成这样:

  1. public class ServiceImpl implements Service{  
    
        @Override
    public void sayHello() {
    ServiceFactory.before();
    System.out.println("Hello world!");
    ServiceFactory.after();
    } @Override
    public void sayBye() {
    ServiceFactory.before();
    System.out.println("Bye bye!");
    ServiceFactory.after();
    } @Override
    public void sayHi() {
    ServiceFactory.before();
    System.out.println("Hi");
    ServiceFactory.after(); ServiceFactory.other();
    }
    }

这样代码,感觉是少了一些,但是我们的原则是尽量 别重复同样的代码,提高代码的复用性,改动最小为基准。也许业务很复杂,比较多,那么你要重复多少代码,整个类要写得多麻烦所啊!如果到时候有些假设before 和after 需要变化位置,你又要改动多少呢?

当然,目前的的JDK (大于1.3)为了解决这些问题,为我们提供的反射机制,动态代理机制。看看如何更好的解决这个问题。这里先copy 下,什么是代理:

Java的动态代理机制
代理模式是常用的Java设计模式。代理类主要负责为委托类预处理消息、过滤信息、把消息转发给委托类,以及事后处理信息等。
    理论 - -总是那么抽象(~。~),简单点说,就是:1.我的目的是去学校,那么校服 早餐 校车,这些我都需要,但是不由我做,全部代理给我父母搞定了(当然我是自己搞定的。)2.再简单的说就是:我只关注我主要的事情,其他附加的事情,全部交给别人搞定。看代码..

MyPorxy 我的代理类:

  1. import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy; public class MyProxy implements InvocationHandler{ // 目标对象,也就是我们主要的业务,主要目的要做什么事
    private Object delegate; /**
    * 和你额外需要做得事情,进行绑定,返回一个全新的对象(写法,基本上固定的)
    * @param delegate
    * @return
    */
    public Object bind(Object delegate){
    this.delegate = delegate;
    return Proxy.newProxyInstance(this.delegate.getClass().getClassLoader(),
    this.delegate.getClass().getInterfaces(), this);
    } /**
    * 你刚才需要执行的方法,都需要通过该方法进行动态调用
    */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
    Object obj = null;
    // 执行前置的方法
    ServiceFactory.before();
    // 通过反射,执行目标方法,也就是你的主要目的
    obj = method.invoke(this.delegate, args);
    // 执行后置的方法
    ServiceFactory.after();
    // 返回值给调用者
    return obj;
    } }

这里运用的反射知识,还需要去看看,这里就不解释了。

ServiceImpl 变化:

  1. public class ServiceImpl implements Service{  
    
        @Override
    public void sayHello() {
    System.out.println("Hello world!");
    } @Override
    public void sayBye() {
    System.out.println("Bye bye!");
    } @Override
    public void sayHi() {
    System.out.println("Hi");
    }
    }

测试类:

  1. public class Test {  
    
        /**
    * 测试类
    * @param args
    */
    public static void main(String[] args) {
    // 不启用代理
    //Service service = new ServiceImpl();
    // 使用代理
    Service service = (Service)new MyProxy().bind(new ServiceImpl()); service.sayHello();
    service.sayBye();
    service.sayHi();
    }
    }

OK,那么你现在看看,我们的业务实现类ServiceImpl 是不是干净多了,代码是不是在某些地方见过呢?即时你再进行添加更多的方法,也可以同样实现了对吗?当然,在Test里面,假设我们有的方法想用,有的方法不想用,那么又该怎么实现呢?

Spring AOP 学习(一) 代理模式的更多相关文章

  1. Spring AOP 和 动态代理技术

    AOP 是什么东西 首先来说 AOP 并不是 Spring 框架的核心技术之一,AOP 全称 Aspect Orient Programming,即面向切面的编程.其要解决的问题就是在不改变源代码的情 ...

  2. Spring AOP 学习例子

    http://outofmemory.cn/code-snippet/3762/Spring-AOP-learn-example     工作忙,时间紧,不过事情再多,学习是必须的.记得以前的部门老大 ...

  3. Spring AOP学习笔记

      Spring提供了一站式解决方案:          1) Spring Core  spring的核心功能: IOC容器, 解决对象创建及依赖关系          2) Spring Web ...

  4. 在Intellij上面导入项目 & AOP示例项目 & AspectJ学习 & Spring AoP学习

    为了学习这篇文章里面下载的代码:http://www.cnblogs.com/charlesblc/p/6083687.html 需要用Intellij导入一个已有工程.源文件原始内容也可见:link ...

  5. AOP和spring AOP学习记录

    AOP基本概念的理解 面向切面AOP主要是在编译期或运行时,对程序进行织入,实现代理, 对原代码毫无侵入性,不破坏主要业务逻辑,减少程序的耦合度. 主要应用范围: 日志记录,性能统计,安全控制,事务处 ...

  6. 深入理解Spring AOP之二代理对象生成

    深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...

  7. 2018.12.24 Spring中的aop演示(也就是运用aop技术实现代理模式)

    Aop的最大意义是:在不改变原来代码的前提下,也不对源代码做任何协议接口要求.而实现了类似插件的方式,来修改源代码,给源代码插入新的执行代码. 1.spring中的aop演示 aop:面向方面编程.不 ...

  8. Spring AOP学习笔记04:AOP核心实现之创建代理

    上文中,我们分析了对所有增强器的获取以及获取匹配的增强器,在本文中我们就来分析一下Spring AOP中另一部分核心逻辑--代理的创建.这部分逻辑的入口是在wrapIfNecessary()方法中紧接 ...

  9. AOP 技术原理——代理模式全面总结

    前言 非常重要的一个设计模式,也很常见,很多框架都有它的影子.定义就不多说了.两点: 1.为其它对象提供一个代理服务,间接控制对这个对象的访问,联想 Spring 事务机制,在合适的方法上加个 tra ...

随机推荐

  1. Play on Words UVA - 10129 欧拉路径

    关于欧拉回路和欧拉路径 定义:欧拉回路:每条边恰好只走一次,并能回到出发点的路径欧拉路径:经过每一条边一次,但是不要求回到起始点 ①首先看欧拉回路存在性的判定: 一.无向图每个顶点的度数都是偶数,则存 ...

  2. 基于JS实现回到页面顶部的五种写法(从实现到增强)

    这篇文章主要介绍了基于JS实现回到页面顶部的五种写法(从实现到增强)的相关资料,本文介绍的非常详细,实用性也非常高,非常具有参考借鉴价值,需要的朋友可以参考下   写法 [1]锚点 使用锚点链接是一种 ...

  3. Mybatis+MSSql插入数据的同时并获取自增的ID

    在项目中遇到这样的情况,新增一个角色,这个角色有某些权限,这两个数据存在不同的表中,一个是sys_role,另外一个是sys_role_permission表,注意,现在的逻辑是这样的 1,在表sys ...

  4. js获取屏幕的大小等信息

    <html><script>function a(){document.write("屏幕分辨率为:"+screen.width+"*" ...

  5. Python之图片格式转换

    import os import shutil from PIL import Image def getAllFiles(dirName, houzhui=' '): results = [] fo ...

  6. Mysql配置文件读取顺序

    On Unix, Linux and Mac OS X, MySQL programs read startup options from the following files, in the sp ...

  7. OBS (open boardcast server)结构分析

    一,简介 OBS(open boardcast server),是一个用于直播的开源软件. 官方网站:https://obsproject.com/ 代码托管地址:https://github.com ...

  8. OpenCV学习笔记十七:opencv_bioinspired模块

    一,简介: 该库是基于仿生学的图像/视频处理库,目前包含模拟人类视网膜的算法.

  9. aspx.cs方法设置webmenthod特性接收ajax请求

    cs代码: public partial class TelerikWebMethod : BasePage//System.Web.UI.Page { protected void Page_Loa ...

  10. 45、Android事件总线分发库的使用

    事件总线分发库EventBus和Otto的简介及对比 什么是事件总线管理: a.将事件放到队列里,用于管理和分发b.保证应用的各个部分之间高效的通信及数据.事件分发c.模块间解耦 Event Bus是 ...