Spring 框架基础(04):AOP切面编程概念,几种实现方式演示
本文源码:GitHub·点这里 || GitEE·点这里
一、AOP基础简介
1、切面编程简介
AOP全称:Aspect Oriented Programming,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。核心作用:可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的复用性和开发效率。AOP提供了取代继承和委托的一种新的方案,而且使用起来更加简洁清晰,是软件开发中的一个热点理念。
2、AOP术语

(1)、通知类型:Advice
前置通知[Before]:目标方法被调用之前;
返回通知[After-returning]:目标方法执行成功之后;
异常通知[After-throwing]:在目标方法抛出异常之后;
后置通知[After]:目标方法完成之后;
环绕通知[Around]:在目标方法执行前后环绕通知;
(2)、连接点:JoinPoint
程序执行的某一个特定位置,如类初始前后,方法的运行前后。
(3)、切点:Pointcut
连接点是指那些在指定策略下可能被拦截到的方法。
(4)、切面:Aspect
切面由切点和通知的结合。
(5)、引入:Introduction
特殊的增强,为类添加一些属性和方法。
(6)、织入:Weaving
将增强添加到目标类的具体连接点上的过程。编译期织入,这要求使用特殊编译器;类装载期织入,这要求使用特殊的类加载器;动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring采用的是动态代理织入,而AspectJ采用编译期织入和类装载期织入。
(7)、代理:Proxy
类被AOP织入后生成一个结果类,它是融合了原类和增强逻辑的代理类。
二、AOP编程实现方式
案例基于如下类进行:
public class Book {
private String bookName ;
private String author ;
}
public interface BookService {
void addBook (Book book) ;
}
public class BookServiceImpl implements BookService {
@Override
public void addBook(Book book) {
System.out.println(book.getBookName());
System.out.println(book.getAuthor());
}
}
1、JDK动态代理
public class BookAopProxyFactory {
public static BookService createService() {
// 目标类
final BookService bookService = new BookServiceImpl() ;
// 切面类
final BookAspect bookAspect = new BookAspect();
/*
* 代理类:将目标类(切入点)和 切面类(通知) 结合
*/
BookService proxyBookService = (BookService) Proxy.newProxyInstance(
BookAopProxyFactory.class.getClassLoader(),
bookService.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// 前执行
bookAspect.before();
// 执行目标类的方法
Object obj = method.invoke(bookService, args);
// 后执行
bookAspect.after();
return obj;
}
});
return proxyBookService ;
}
}
2、CgLib字节码增强
采用字节码增强框架cglib,在运行时创建目标类的子类,从而对目标类进行增强。
public class BookAopCgLibFactory {
public static BookService createService() {
// 目标类
final BookService bookService = new BookServiceImpl() ;
// 切面类
final BookAspect bookAspect = new BookAspect();
// 核心代理类
Enhancer enhancer = new Enhancer();
// 确定父类
enhancer.setSuperclass(bookService.getClass());
// 设置回调函数
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method,
Object[] args,
MethodProxy methodProxy) throws Throwable {
bookAspect.before();
Object obj = method.invoke(bookService, args);
bookAspect.after();
return obj;
}
});
BookServiceImpl proxyService = (BookServiceImpl) enhancer.create();
return proxyService ;
}
}
3、Spring半自动代理
spring 创建代理对象,从spring容器中手动的获取代理对象。
- 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- 创建代理类 -->
<bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.spring.mvc.service.BookService" />
<property name="target" ref="bookService" />
<property name="interceptorNames" value="myAspect" />
</bean>
- 切面类
public class BookAopSpringHalf implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method Before ...");
Object obj = methodInvocation.proceed();
System.out.println("Method After ...");
return obj;
}
}
4、Spring全自动代理
从spring容器获得目标类,如果配置Aop,spring将自动生成代理。
- 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- AOP编程配置 -->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.spring.mvc.service.*.*(..))"
id="myPointCut"/>
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>
5、综合测试
@Test
public void test1 (){
BookService bookService = BookAopProxyFactory.createService() ;
Book book = new Book() ;
book.setBookName("Spring实战");
book.setAuthor("Craig Walls");
bookService.addBook(book);
}
@Test
public void test2 (){
BookService bookService = BookAopCgLibFactory.createService() ;
Book book = new Book() ;
book.setBookName("MySQL");
book.setAuthor("Baron");
bookService.addBook(book);
}
@Test
public void test3 (){
String xmlPath = "spring-aop-half.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) context.getBean("proxyFactory");
Book book = new Book() ;
book.setBookName("红楼梦");
book.setAuthor("曹雪芹");
bookService.addBook(book);
}
@Test
public void test4 (){
String xmlPath = "spring-aop-all.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) context.getBean("bookService");
Book book = new Book() ;
book.setBookName("西游记");
book.setAuthor("吴承恩");
bookService.addBook(book);
}
三、AspectJ切面编程
1、基础简介
AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持,通过JDK5注解技术,允许直接在类中定义切面,新版本Spring框架,推荐使用AspectJ方式来开发AOP编程。
2、XML配置方式
- 切面类
public class BookAopAspectJ {
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:" + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕通知前");
Object obj = joinPoint.proceed();
System.out.println("环绕通知前后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
- 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopAspectJ" />
<!-- 配置AOP编程 -->
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut expression="execution(* com.spring.mvc.service.impl.BookServiceImpl.*(..))" id="myPointCut"/>
<!-- 前置通知-->
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<!-- 后置通知 -->
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
<!-- 环绕通知 -->
<aop:around method="myAround" pointcut-ref="myPointCut"/>
<!-- 抛出异常 -->
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
<!-- 最终通知 -->
<aop:after method="myAfter" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
- 测试方法
@Test
public void test1 (){
String xmlPath = "spring-aop-aspectj-01.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) context.getBean("bookService");
Book book = new Book() ;
book.setBookName("三国演义");
book.setAuthor("罗贯中");
bookService.addBook(book);
}
3、注解扫描方式
- 配置文件
<!-- 开启类注解的扫描 -->
<context:component-scan base-package="com.spring.mvc.service.impl" />
<!-- 确定AOP注解生效 -->
<aop:aspectj-autoproxy />
<!-- 声明切面 -->
<bean id="myAspect" class="com.spring.mvc.config.AuthorAopAspectJ" />
<aop:config>
<aop:aspect ref="myAspect" />
</aop:config>
- 注解切面类
@Component
@Aspect
public class AuthorAopAspectJ {
@Pointcut("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
private void myPointCut(){
}
@Before("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:" + joinPoint.getSignature().getName());
}
@AfterReturning(value="myPointCut()" ,returning="ret")
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知:" +
joinPoint.getSignature().getName() + " , -->" + ret);
}
@Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕通知前");
Object obj = joinPoint.proceed();
System.out.println("环绕通知前后");
return obj;
}
@AfterThrowing(
value="execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))",
throwing="e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
@After("myPointCut()")
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
- 测试方法
@Test
public void test2 (){
String xmlPath = "spring-aop-aspectj-02.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
AuthorService authorService = (AuthorService) context.getBean("authorService");
System.out.println("作者:"+authorService.getAuthor());
}
四、源代码地址
GitHub·地址
https://github.com/cicadasmile/spring-mvc-parent
GitEE·地址
https://gitee.com/cicadasmile/spring-mvc-parent

Spring 框架基础(04):AOP切面编程概念,几种实现方式演示的更多相关文章
- Spring 框架基础(05):事务管理机制,和实现方式
本文源码:GitHub·点这里 || GitEE·点这里 一.Spring事务管理 1.基础描述 Spring事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用jav ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
- Spring AOP 切面编程记录日志和接口执行时间
最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特 ...
- SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...
- Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入
首选需要参考的是:[参考]http://www.cnblogs.com/guokai870510826/p/5977948.html http://www.cnblogs.com/guokai8 ...
- Spring框架基础
1 Spring框架 1.1 Spring的基本概念 是一个轻量级的框架,提供基础的开发包,包括消息.web通讯.数据库.大数据.授权.手机应用.session管理 ...
- AOP 切面编程------JoinPoint ---- log日志
AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件 ...
- Spring框架基础2
Spring框架基础2 测试Spring的AOP思想和注解的使用 导包(在前面的基础上添加) SpringAOP名词解释 AOP编程思想:横向重复代码,纵向抽取:就是说多个地方重复的代码可以抽取出来公 ...
- Spring框架入门之AOP
Spring框架入门之AOP 一.Spring AOP简单介绍 AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented ...
随机推荐
- (一)spring 高级装配-@Profile
1.环境与profile 示例:数据库配置 a:通过@Bean注解,通过EmbeddedDatabaseBuilder创建数据源 @Bean(destroyMethod="shutdown& ...
- 词义消除歧义NLP项目实验
词义消除歧义NLP项目实验 本项目主要使用https://github.com/alvations/pywsd 中的pywsd库来实现词义消除歧义 目前,该库一部分已经移植到了nltk中,为了获得更好 ...
- [C++] 重载运算符与类型转换(1)
1.形式:返回值 operator符号(参数列表){} 2.不能被重载的运算符::: 作用域运算符 .* . 成员访问运算符 ?: 条件运算符:某些运算符(逗号,,取地址&, ...
- 使用flask-mail扩展发送邮件
使用flask-mail扩展发送电子邮件 在我们开发完web系统后,一些特定的事件发生时,系统要自动发送相关邮件至管理员,运维人员和其他相关人员.python标准库中的smtplib包也可以用在Fla ...
- Hadoop核心组件之HDFS
HDFS:分布式文件系统 一句话总结 一个文件先被拆分为多个Block块(会有Block-ID:方便读取数据),以及每个Block是有几个副本的形式存储 1个文件会被拆分成多个Block blocks ...
- c#学习路线应该靠谱
因为学c/c++,找不到工作.想转c#,搜索得到的学习路线 C#入门经典 C#数据库入门经典 C#高级编程 ADO.net高级编程 基础的东西搞明白之后,可以学习设计模式,C#设计模式 你是说深入的书 ...
- Java 8 时间日期使用
一.日期时间 Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理.java.util.Date和SimpleDateFormatter都不是线程安全的 ...
- 003-python函数式编程,模块
1.函数式编程 1.1 高阶函数 把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式 函数名也是变量,函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函 ...
- Python基础(十八)
今日主要内容 包 一.包 (一)什么是包 只要是含有__init__.py文件的文件夹就是一个包 包的本质其实就是一个文件夹,利用包将不同功能的模块组织起来,以此来提高程序的结构性和可维护性 包是用来 ...
- Linux之修改系统密码
目录 Linux之修改系统密码 参考 RHEL6修改系统密码 RHEL7修改系统密码 Linux之修改系统密码