本文源码: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切面编程概念,几种实现方式演示的更多相关文章

  1. Spring 框架基础(05):事务管理机制,和实现方式

    本文源码:GitHub·点这里 || GitEE·点这里 一.Spring事务管理 1.基础描述 Spring事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用jav ...

  2. AOP面向切面编程的四种实现

     一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...

  3. Spring AOP 切面编程记录日志和接口执行时间

    最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特 ...

  4. SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务

    本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...

  5. Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入

    首选需要参考的是:[参考]http://www.cnblogs.com/guokai870510826/p/5977948.html    http://www.cnblogs.com/guokai8 ...

  6. Spring框架基础

    1         Spring框架 1.1           Spring的基本概念 是一个轻量级的框架,提供基础的开发包,包括消息.web通讯.数据库.大数据.授权.手机应用.session管理 ...

  7. AOP 切面编程------JoinPoint ---- log日志

    AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件 ...

  8. Spring框架基础2

    Spring框架基础2 测试Spring的AOP思想和注解的使用 导包(在前面的基础上添加) SpringAOP名词解释 AOP编程思想:横向重复代码,纵向抽取:就是说多个地方重复的代码可以抽取出来公 ...

  9. Spring框架入门之AOP

    Spring框架入门之AOP 一.Spring AOP简单介绍 AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented ...

随机推荐

  1. servlet request、response的中文乱码问题

    一.request 1.get请求 get请求的参数是在请求行中的,浏览器使用utf-8进行编码,数据的编码一般为UTF-8,而url请求行的默认编码为ISO-8859-1,一般来说有以下方式可以解决 ...

  2. 搭建数据库galera集群

    galera集群 galera简介 galera集群又叫多主集群,用于数据库的同步,保证数据安全 最少3台,最好是奇数台数,当一台机器宕掉时,因为仲裁机制,这台机器就会被踢出集群. 通过wsrep协议 ...

  3. 【linux】查看系统内存占用

    1.查看内存情况 free -h 解释下基本概念 Mem 内存的使用信息Swap 交换空间的使用信息total 系统总的可用物理内存大小used 已被使用的物理内存大小free 还有多少物理内存可用s ...

  4. WordPress对接微信小程序遇到的问题

    1.文章内容中的“<”和“>”字符显示问题 小程序是使用“wxPares工具来实现html转wxml的,如果你的文本包含了代码比如xml会携带<>符号,程序会将其转化,造成解析 ...

  5. 程序员写 2000 行 if else?领导:这个锅我不背

    前言 知乎上有小伙伴提了这么一个问题,如何看待陕西省普通话水平测试成绩查询系统?查询系统前端代码就直接给出了身份账号,姓名,证书编号,如果信息是真的,就泄露了这么多考生的信息,白给那种.为什么会发生这 ...

  6. mysql 排序规则

    一.对比 1.utf8_general_ci 不区分大小写,utf8_general_cs 区分大小写 2.utf8_bin: compare strings by the binary value ...

  7. 多tomcat服务和nginx负载均衡配置

    1.nginx服务安装及配置,详见:linux 配置之安装nginx 2.多个tomcat服务安装及配置,详见:linux 配置多个tomcat 3.关键配置nginx.conf文件 http { i ...

  8. FastDfs之StorageServer的详细配置介绍

    #这个配置文件是否失效 disabled=false #false为有效 true为无效 # 本storage server所属的group名 group_name=group1 # 可以版定一个ip ...

  9. .Net Core 商城微服务项目系列(五):使用Polly处理服务错误

    项目进行微服务化之后,随之而来的问题就是服务调用过程中发生错误.超时等问题的时候我们该怎么处理,比如因为网络的瞬时问题导致服务超时,这在我本人所在公司的项目里是很常见的问题,当发生请求超时问题的时候, ...

  10. SUSE CaaS Platform 4 - 简介

    SUSE CaaS Platform KUBERNETES - 面向企业 SUSE CaaS Platform 是一款企业级容器管理解决方案,可让 IT 和 DevOps 专业人士更轻松地部署.管理和 ...