Spring笔记:AOP基础

AOP

引入AOP

  面向对象的开发过程中,我们对软件开发进行抽象、分割成各个模块或对象。例如,我们对API抽象成三个模块,Controller、Service、Command,这很好地解决了业务级别的开发,但是对于系统级别的开发我们很难聚集。比如每一个模块需要打印日志、代码监控、异常检测等。我们只能将日志代码嵌套在各个对象上,无法关注日志本身

  为了更好地将系统系统级别的代码抽离出来,去掉和对象的耦合,就产生了AOP(面向切面)。如下图,OOP是一种横向扩展,AOP是一种纵向扩展。AOP依赖OOP,进一步将系统级别的代码抽象出来,进行纵向排列,实现低耦合

AOP的家庭成员

  •  PointCut::即在哪个地方进行切入,它可以指定一个点,也可以指定多个点。
  •  Advice:连接点,在切入点(PointCut)干什么,比如打印日志、执行缓存、处理异常等。
  •  Advisor/Aspect:PointCut与Advice形成了切面Aspect,这个概念本身即代表切面的所有元素,Proxy技术会将切面植入到代码中。
  •  Proxy:代理,相当于一个管理部分,它管理了AOP如何融入OOP。

NOTE:Aspect虽然是面向切面核心思想的重要组成部分,但是其思想的践行者是Proxy,也是实现AOP的难点与核心所在。

技术实现Proxy

静态代理

  设计模式中讲过代理模式,此处不在赘述。

  之所以称为静态dialing,是因为静态与动态是有代理产生的时间来决定,静态代理产生于代码编译阶段,即一旦代码运行就不变了

  

  举个例子,我们实现一个简单的日志管理系统:

public interface IPerson {
public void doSomething();
}
public class Person implements IPerson {
public void doSomething(){
System.out.println("I want wo sell this house");
}
}
public class PersonProxy {
private IPerson iPerson;
private final static Logger logger = LoggerFactory.getLogger(PersonProxy.class); public PersonProxy(IPerson iPerson) {
this.iPerson = iPerson;
}
public void doSomething() {
logger.info("Before Proxy");
iPerson.doSomething();
logger.info("After Proxy");
} public static void main(String[] args) {
PersonProxy personProxy = new PersonProxy(new Person());
personProxy.doSomething();
}
}

  通过代理类我们可以将日志代码集成到了目标类,但从上面我们可以看出它具有很大的局限性:需要固定的类编写接口(或许还可以接受,毕竟有提倡面向接口编程),需要实现接口的每一个函数(不可接受),同样会造成代码的大量重复,将会使代码更加混乱

动态代理

  SpringAOP是动态代理的典范,我们需要先熟悉一下动态代理的相关概念

  Mybatis中,Mapper仅仅是一个接口,而不是一个包含逻辑的实现类,我们知道一个接口是无法去执行的,那么它是如何运行的呢?这不是违反了教科书所说的接口不能运行的道理吗?

  答案就是动态代理,不妨先来看一下Mapper到底是什么东西。

  很显然Mapper产生了代理类,这个代理类是MyBatis为我们创建

代理模式

  所谓的代理模式就是在原有的服务上多加了一个占位,通过这个占位去控制服务的访问

  举例子,假设你是一个公司的工程师,能提供一些技术服务,公司的客服是一个美女,他不懂技术。而我是一个客户,徐你们公司提供技术服务。显然,我只会找你们公司的客服,和客服沟通,而不是找你沟通。客服会根据公司的规章制度和业务规则来决定找不找你服务。那么此时客服就等同于你的代理,她通过和我的交流来控制对你的访问,当然他也可以提供一些你们公司对外的服务。而我只能通知他的代理访问你。对我而言,我跟本不需要认识你,只需要认识客服就可以了。事实上,站在我的角度,我会认为客服就是代表你们公司,而不管真正为我服务的你是怎么样的

  其次,为什么要用代理模式呢?通过代理可以控制如何访问真正的服务对象,提供额外的服务。另外有机会通过重写一些类来满足特定的需要,正如客服也可以根据公司的业务规则,提供一些服务,这个时候就不需要你劳你大驾了。

  一般来说,代理分为两种,一种是JDK反射机制提供的代理,另一种是CGLIB代理

JDK动态代理

  JDK的动态代理,是由JDK的Java.lang.reflect包提供支持的,我们需要完成几个步骤:

  •   编写服务类和接口,这个是真正的服务提供者,在JDK代理中接口是必须的。
  •   编写代理类,提供绑定和代理方法。

  JDK最大的缺点就是需要提供接口,而MyBatis的Mapper就是一个接口它采用的就是JDK的动态代理。我们先给一个服务接口。

public interface HelloService{
public void sayHello(String name);
}

  然后,写一个实现类

public class HelloServiceImpl implements HelloService{
public void sayHello(String name)
{
System.out.println("Hello"+name);
}
}

  现在我们写一个代理类,提供真实对象的绑定和代理方法。代理类的要求是实现InvocationHandler接口的代理方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class HelloServiceProxy implements InvocationHandler
{
/**
* 真实服务对象
*/
private Object target; /**
* 绑定委托对象,并返回一个代理类
* @param target
* @return
*/
public Object bind(HelloService target)
{
this.target=target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
} /**
*
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("*****我是JDK动态代理*****");
Object result = null;
//反射方法前调用
System.out.println("我准备说Hello");
//执行方法,相当于调用HelloServiceImp类的sayHello方法
result = method.invoke(target,args);
//反射方法后调用
System.out.println("我说过Hello了");
return result;
} }

 下面这段代码让JDK产生一个代理对象,第一个参数是类加载器,第二个参数是接口(代理对象挂在哪一个接口下),第三个参数代表当前类,表示使用当前类的代理方法作为对象的代理执行者

  Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

 一旦绑定后,在进入代理对象方法调用的时候就会到HelloServiceProxy的代理方法上,代理方法有三个参数,第一个proxy是代理对象,第二个是当前调用的方法、第三个是方法的参数

 我们可以用下面这段代码测试一下动态代理的效果:

public class HelloServiceMain {
public static void main(String[] args) {
HelloServiceProxy helloHandler = new HelloServiceProxy();
HelloService proxy = (HelloService) helloHandler.bind(new HelloServiceImpl());
proxy.sayHello(",ms");
}
}

效果是这样的:

输出:
*****我是JDK动态代理*****
我准备说Hello
Hello,ms
我说过Hello了

CGLIB动态代理

  JDK提供的动态代理存在一个缺陷,就是你必须提供接口才可以使用,为了克服缺陷,我们可以使用开源框架——CGLIB,它是一种流行的动态代理。

Spring笔记:AOP基础的更多相关文章

  1. Spring 学习笔记 IoC 基础

    Spring IoC Ioc 是什么 IoC -- Inversion of Control(控制反转)什么是控制?什么是反转? 控制反转了什么? 在很早之前写项目不用 Spring 的时候,都是在 ...

  2. [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

    前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习 ...

  3. [Spring框架]Spring AOP基础入门总结一.

    前言:前面已经有两篇文章讲了Spring IOC/DI 以及 使用xml和注解两种方法开发的案例, 下面就来梳理一下Spring的另一核心AOP. 一, 什么是AOP 在软件业,AOP为Aspect ...

  4. CgLib动态代理学习【Spring AOP基础之一】

    如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...

  5. Spring基础篇——Spring的AOP切面编程

    一  基本理解 AOP,面向切面编程,作为Spring的核心思想之一,度娘上有太多的教程啊.解释啊,但博主还是要自己按照自己的思路和理解再来阐释一下.原因很简单,别人的思想终究是别人的,自己的理解才是 ...

  6. Java基础-SSM之Spring的AOP编程

    Java基础-SSM之Spring的AOP编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   Spring的本质说白了就是动态代理,接下来我们会体验AOP的用法.它是对OOP的 ...

  7. Spring笔记:IOC基础

    Spring笔记:IOC基础 引入IOC 在Java基础中,我们往往使用常见关键字来完成服务对象的创建.举个例子我们有很多U盘,有金士顿的(KingstonUSBDisk)的.闪迪的(SanUSBDi ...

  8. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  9. Spring中AOP原理,源码学习笔记

    一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...

随机推荐

  1. PHP下载远程文件的3种方法以及性能考虑

    今天在做导出Excel的时候,总是要测试导出的Excel文件,频繁的下载和打开,很麻烦 就想着写段代码一气呵成  服务端导出Excel==>下载Excel文件到本地==>并打开的操作. 这 ...

  2. neocomplcache 自动补全

    key description ctrl+n 当前词补全项,下一个 ctrl+p 当前词补全项,上一个 :help NERDTree NERDTree帮助手册

  3. Response设置response header

    total : #常见状态码:服务器处理请求的结果状态 200 : 表示请求处理完成并完美返回; 302 : 表示请求需要进一步细化; 404 : 表示客户访问资源Not Found; 500 : 表 ...

  4. nginx 用法

    nginx配置location总结及rewrite规则写法 如何将 /health 重定向到 /health.html https://stackoverflow.com/questions/4614 ...

  5. ThinkPHP自动填充实现无限级分类的方法

    这篇文章主要介绍了ThinkPHP自动填充实现无限级分类的方法,是ThinkPHP项目开发中非常实用的一个技巧,需要的朋友可以参考下   本文实例展示了ThinkPHP自动填充实现无限级分类的方法,是 ...

  6. 结果集(ResultSet)用法

    结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等. 结果集读取数据 ...

  7. python 爬虫实战4 爬取淘宝MM照片

    本篇目标 抓取淘宝MM的姓名,头像,年龄 抓取每一个MM的资料简介以及写真图片 把每一个MM的写真图片按照文件夹保存到本地 熟悉文件保存的过程 1.URL的格式 在这里我们用到的URL是 http:/ ...

  8. wchar与char字符转换的探究

    在Xcode 模拟器环境下.測试wchar_t与char的转换: void convert_test() { setlocale(LC_ALL, "zh_CN.UTF-8"); c ...

  9. Android-ViewPagerIndicator框架使用——TitlePageIndicator

    前言:TitlePageIndicator这个就是效果比较好. 一:定义布局文件simple_titles: <LinearLayout xmlns:android="http://s ...

  10. GoogleMap-------manifest文件配置

    前言:在使用GoopleMap之前需要配置manifest文件 1.这个可有可无,com.xhm.meishi是项目的包名 <!-- 声明调用这个应用需要的权限 --> <permi ...