AOP简介

  1. AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.。

  2. AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.。

  3. 在应用 AOP 编程时, 仍然需要定义通用的系统功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里。

  AOP的优点:

    • 日志记录的代码和真正的业务逻辑代码进行代码分离
    • 通用的系统功能(日志记录、权限校验)进行了高度的模块化
    •  业务逻辑的功能变的更简洁,仅仅包含业务逻辑的代码
    •  AOP可以将系统功能(日志记录)与业务逻辑功能搅和到一起执行


AOP 中的专业术语

  • 切面(aspect):横切逻辑被模块化的特殊对象。即它是一个类 :如LogAspect
  • 通知(advice):切面中必须完成的工作。即它是类中的一个方法:如writeLog()
  • 目标类(target):被通知增强的对象
  • 代理类(proxy):向目标类应用通知增强之后产生的对象
  • 切入点(pointcut):切面中通知执行的“地点”的定义
  • 连接点(JoinPoint): 与切入点匹配的执行点:如目标类中的所有方法getUserId()


AOP的两种底层实现方式

  代理:

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

      •     静态代理:

为每一个目标对象创建一个代理实现类的方式可以认为就是静态代理。

静态代理的实现很简单,但是会造成代理类的快速膨胀,每一个目标类,都需要创建一个代理类

 //静态代理
public class StaticProxyUserService implements UserService {
//原始对象
private UserService userService; public StaticProxyUserService(UserService userService) {
this.userService = userService;
}
@Override
public User getById(String userId) {
System.out.println("执行权限校验,日志记录.......");
return userService.getById(userId);
}
@Override
public boolean add(User user) {
System.out.println("执行权限校验,日志记录.......");
return userService.add(user);
} @Override
public boolean delete(String userId) {
System.out.println("执行权限校验,日志记录.......");
return userService.delete(userId);
}
@Override
public boolean update(User user) {
System.out.println("执行权限校验,日志记录.......");
return userService.update(user);
}
}
      •    动态代理:

为了解决静态代理的缺点,就产生了动态代理:在系统运行时,动态生成一个持有原始对象,并实现代理接口的Proxy,同时 “植入”通用逻辑(日志、权限等)。

动态代理可以实现静态代理相同的功能,唯一的区别这些Proxy的创建都是自动的并且在系统运行时生成的。这样就不需要对每一个原始对象来创建一个代理了。

 JDK动态代理

JDK内置的Proxy动态代理可以在运行时动态生成字节码,而没必要针对每个类编写代理类。中间主要使用到了一个接口InvocationHandler与Proxy.newProxyInstance静态方法。

使用内置的Proxy(JDK动态代理)实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。

如果项目中有些类没有实现接口,则不应该为了实现动态代理而刻意去抽出一些没有实例意义的接口,通过cglib可以解决该问题。

    1.  创建maven工程并解决jdk版本及web.xml问题

    2.  导入jar包

  <properties>
<spring-version>4.2.4.RELEASE</spring-version>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 设置jdk的编译版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>

    3.  编写切面类(封装增强逻辑)

 //切面:定义了增强的业务逻辑(权限验证)
public class SecurityAspect {
//权限校验的系统逻辑
public void checkPrivilege(){
System.out.println("我是权限校验的方法,我需要在方法执行前进行执行");
}
}

    4.  创建代理对象

 public class ProxyFactory implements InvocationHandler{
//目标类
private Object target; //传递目标对象
public ProxyFactory(Object target) {
super();
this.target = target;
} public Object getProxy(){
/**
* loader:类加载器
* interfaces:目标实现类接口(jdk动态代理必须有接口)
* h:实现了InvocationHandle接口的类
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//添加校验权限的逻辑
SecurityAspect securityAspect = new SecurityAspect();
//添加检验权限
securityAspect.checkPrivilege();
//反射调用业务逻辑方法(目标类,参数)
Object result = method.invoke(target, args);
return result;
}
}

    5.  测试

 public static void main(String[] args) {
//测试动态代理的执行
UserService target = new UserServiceImpl();
//产生代理对象
UserService proxy = (UserService) new ProxyFactory(target).getProxy();
//调用代理对象的业务方法
proxy.add();
}

 CGLIB动态代理

CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码。

使用cglib完成动态代理,大概的原理是:cglib继承被代理的类(UserServiceImpl),重写方法,织入通知,动态生成字节码并运行,因为是继承所以final类是没有办法动态代理的。

      1.  定义目标类(不需要实现接口)

 /**
* cglib的目标类
* 没有实现接口,只是一个业务类
*/
public class UserServiceCglib {
//切入点
//业务逻辑方法
public void add(){
System.out.println("cglib的add方法被调用...");
}
}

    

      2.  定义切面类(增强逻辑类)

 /**
* 增强逻辑类:日志记录切面
*/
public class LogAspect {
//通知
//增强的业务逻辑
public void log(){
System.out.println("日志记录... ...");
}
}

      3.  定义cglib动态代理生成器

 /**
* cglib动态代理类生成器
*/
public class CglibProxyFactory implements MethodInterceptor{
//目标对象
private Object target; //有参构造器
public CglibProxyFactory(Object target) {
super();
this.target = target;
} //获取代理类的方法
public Object getProxy(){
//调用cglib产生代理对象
Enhancer enhancer = new Enhancer();
//设置父类的类型
enhancer.setSuperclass(target.getClass());
//设置回调方法
enhancer.setCallback(this); //产生代理对象
Object proxy = enhancer.create();
return proxy;
} //拦截业务方法的执行
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//添加增强逻辑
//添加日志
LogAspect logAspect = new LogAspect();
logAspect.log(); //执行业务逻辑方法
Object result = methodProxy.invokeSuper(o, args);
return result;
}
}

      4.  测试

 public static void main(String[] args) {
//创建目标对象
UserServiceCglib target = new UserServiceCglib();
//获取目标对象的代理对象
UserServiceCglib proxy = (UserServiceCglib) new CglibProxyFactory(target).getProxy();
proxy.add();
}


面向切面编程-AOP的介绍的更多相关文章

  1. Spring框架学习笔记(2)——面向切面编程AOP

    介绍 概念 面向切面编程AOP与面向对象编程OOP有所不同,AOP不是对OOP的替换,而是对OOP的一种补充,AOP增强了OOP. 假设我们有几个业务代码,都调用了某个方法,按照OOP的思想,我们就会 ...

  2. Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)

    在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...

  3. 设计模式之面向切面编程AOP

    动态的将代码切入到指定的方法.指定位置上的编程思想就是面向切面的编程. 代码只有两种,一种是逻辑代码.另一种是非逻辑代码.逻辑代码就是实现功能的核心代码,非逻辑代码就是处理琐碎事务的代码,比如说获取连 ...

  4. Spring学习手札(二)面向切面编程AOP

    AOP理解 Aspect Oriented Program面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 但是,这种说法有些片面,因为在软件工程中,AOP的价值体现的并 ...

  5. Spring学习笔记:面向切面编程AOP(Aspect Oriented Programming)

    一.面向切面编程AOP 目标:让我们可以“专心做事”,避免繁杂重复的功能编码 原理:将复杂的需求分解出不同方面,将公共功能集中解决 *****所谓面向切面编程,是一种通过预编译方式和运行期动态代理实现 ...

  6. Spring之控制反转——IoC、面向切面编程——AOP

      控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...

  7. 【串线篇】面向切面编程AOP

    面向切面编程AOP 描述:将某段代码“动态”的切入到“指定方法”的“指定位置”进行运行的一种编程方式 (其底层就是Java的动态代理)spring对其做了简化书写 场景: 1).AOP加日志保存到数据 ...

  8. 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制

    spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...

  9. [译]如何在ASP.NET Core中实现面向切面编程(AOP)

    原文地址:ASPECT ORIENTED PROGRAMMING USING PROXIES IN ASP.NET CORE 原文作者:ZANID HAYTAM 译文地址:如何在ASP.NET Cor ...

随机推荐

  1. Win10 修改 开始 菜单样式..

    因为不是平板,所以改成了这个样子 下面说步骤... 打开 菜单栏位置... 将快捷方式 拷贝到 里面 来... 快捷方式 以 #开头.是为了 让其排列在最前面.... 快捷方式有个技巧...快捷方式  ...

  2. paraview显示指定时间段的时均图(两种方法)

    方法一: 首先计算以后会得到每个时刻的网格数据,如下图: 但是我们只想要比如最后2s的数据,如果直接导入,paraview会把从0s时刻的数据全部加载,做时均图的时候也就是对整个时间段做时均,不是我们 ...

  3. hdu1286 找新朋友 欧拉函数模板

    首先这一题用的是欧拉函数!!函数!!不是什么欧拉公式!! 欧拉函数求的就是题目要求的数. 关于欧拉函数的模板网上百度一下到处都是,原理也容易找,这里要介绍一下另一个强势模板. 在这一题的讨论里看到的. ...

  4. mysql - VARCHAR与VHAR的区别

    一, 基本介绍 char 和 varchar 两类型类似, 用来存储字符串,不同之处来自于他们的保存和检索的差别, char 属于固定的长度字符类型, 而varchar 属于可变长度的字符类型 值 C ...

  5. Hadoop Ecosytem

    There are a lot of Hadoop related projects which are open sourced and widely used by many componies. ...

  6. Android:Sqlitedatabase学习小结

    今天刚刚学习完Sqlite数据库的基础知识,随即把学到的东西记录下来,以便随后查阅,以下是自己对Sqlite数据库的小结:1.Sqlite简介       Sqlite是一款轻型的数据库,它包含在一个 ...

  7. Beam编程系列之Apache Beam WordCount Examples(MinimalWordCount example、WordCount example、Debugging WordCount example、WindowedWordCount example)(官网的推荐步骤)

    不多说,直接上干货! https://beam.apache.org/get-started/wordcount-example/ 来自官网的: The WordCount examples demo ...

  8. Linux下远程连接工具SSHSecureShellClient的使用

    实际开发中,Linux 服务器都在其他的地方,我们要通过远程的方式去连接 Linux 并操作它,Linux 远程的操作工具有很多,企业中常用的有 Puttty.secureCRT.SSH Secure ...

  9. 安卓获取输入法高度与ViewTreeObserver讲解

    目录 安卓获取输入法高度 前言 清单 开始 ViewTreeObserver讲解 获取输入法高度原理 思路 实现 关于ViewTreeObserver 定义 继承 摘要 获取View高度的三种方法 源 ...

  10. android AIDL服务

    这篇文章http://byandby.iteye.com/blog/1026110我们介绍了android的本地服务:它只能由承载它的应用程序使用.现在我们将介绍如何构建可由其他进程通过 RPC 使用 ...