面向切面编程-AOP的介绍
AOP简介
AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.。
AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.。
在应用 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的介绍的更多相关文章
- Spring框架学习笔记(2)——面向切面编程AOP
介绍 概念 面向切面编程AOP与面向对象编程OOP有所不同,AOP不是对OOP的替换,而是对OOP的一种补充,AOP增强了OOP. 假设我们有几个业务代码,都调用了某个方法,按照OOP的思想,我们就会 ...
- Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)
在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...
- 设计模式之面向切面编程AOP
动态的将代码切入到指定的方法.指定位置上的编程思想就是面向切面的编程. 代码只有两种,一种是逻辑代码.另一种是非逻辑代码.逻辑代码就是实现功能的核心代码,非逻辑代码就是处理琐碎事务的代码,比如说获取连 ...
- Spring学习手札(二)面向切面编程AOP
AOP理解 Aspect Oriented Program面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 但是,这种说法有些片面,因为在软件工程中,AOP的价值体现的并 ...
- Spring学习笔记:面向切面编程AOP(Aspect Oriented Programming)
一.面向切面编程AOP 目标:让我们可以“专心做事”,避免繁杂重复的功能编码 原理:将复杂的需求分解出不同方面,将公共功能集中解决 *****所谓面向切面编程,是一种通过预编译方式和运行期动态代理实现 ...
- Spring之控制反转——IoC、面向切面编程——AOP
控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...
- 【串线篇】面向切面编程AOP
面向切面编程AOP 描述:将某段代码“动态”的切入到“指定方法”的“指定位置”进行运行的一种编程方式 (其底层就是Java的动态代理)spring对其做了简化书写 场景: 1).AOP加日志保存到数据 ...
- 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 ...
- [译]如何在ASP.NET Core中实现面向切面编程(AOP)
原文地址:ASPECT ORIENTED PROGRAMMING USING PROXIES IN ASP.NET CORE 原文作者:ZANID HAYTAM 译文地址:如何在ASP.NET Cor ...
随机推荐
- P2257 YY的GCD (莫比乌斯反演)
[题目链接] https://www.luogu.org/problemnew/show/P2257 // luogu-judger-enable-o2 /* -------------------- ...
- [BZOJ 4923][Lydsy1706月赛]K小值查询
传送门 势能分析平衡树,splay或treap都可以 放个指针版的就跑 #include <bits/stdc++.h> using namespace std; #define rep( ...
- 【算法笔记】B1018 锤子剪刀布
1018 锤子剪刀布 (20 分) 大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示: 现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. ...
- BZOJ - 2005 莫比乌斯水题
\(gcd=k+1\)时,每一个的贡献都是\(2k+1\) \(gcd=1\)时,每一个贡献为\(1\) #include<iostream> #include<algorithm& ...
- PIE SDK图片元素的绘制
1. 功能简介 在数据的处理中会用到图片元素的绘制,利用IPictureElement图片元素接口进行绘制,目前PIE SDK支持IPictureElement元素接口的绘制,下面对图片元素的绘制进行 ...
- 超级详细全截图化VMware 安装ubantu
一,下载镜像 由于ubantu时国外源所以下载十分的缓慢 这里我用清华源下载:https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/18.10/ub ...
- (转)通过shell脚本实现批量添加用户和设置随机密码以及生产环境如何批量添加
通过shell脚本实现批量添加用户和设置随机密码以及生产环境如何批量添加 原文:http://www.21yunwei.com/archives/4773 有一个朋友问我如何批量创建用户和设置密码 , ...
- Beam概念学习系列之SDKs
不多说,直接上干货! https://beam.apache.org/get-started/beam-overview/ Beam SDK 提供了一个统一的编程模型,来处理任意规模的数据集,其中包括 ...
- React.js 小书 Lesson8 - 组件的组合、嵌套和组件树
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson8 转载请注明出处,保留原文链接和作者信息. 继续拓展前面的例子,现在我们已经有了 Heade ...
- 深入理解JavaScript系列(11):执行上下文(Execution Contexts)
简介 从本章开始,我将陆续(翻译.转载.整理)http://dmitrysoshnikov.com/网站关于ECMAScript标标准理解的好文. 本章我们要讲解的是ECMAScript标准里的执行上 ...