简介

AOP(面向切面编程):是一种新的方法论,是对传统OOP(面向对象编程)的补充。

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

AOP的好处:

每个事物逻辑位于一个位置,代码不分散,便于维护和升级。

业务模块更简洁,只包含核心业务的代码。

横切关注点:


AOP练习

Aop关于加减乘除的练习:

定义一个算法接口,含有4个方法,加减乘除。

  1. public interface ArithmeticCalculator(){
  2. //加
  3. double add(double a,double b);
  4. //减
  5. double sub(double a,double b);
  6. //乘
  7. double mul(double a,double b);
  8. //除
  9. double div(double a,double b);
  10. }

Aop思想:

  1. public void before(double a ,double b){
  2. System.out.println(a+"and"+b);
  3. }
  4. public void after(result){
  5. System.out.println("结果是"+result);
  6. }
  7. public double sub(double a, double b){
  8. before(a,b);
  9. double result=a+b;
  10. after(result);
  11. return result;
  12. }

但是,这样做是有一些弊端存在的,比如:

代码混乱:

越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。

代码分散:

以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有模块。

那么,如何解决这些问题呢?

这就需要使用Spring的动态代理模式来完成了。


使用动态代理解决问题

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


Spring AOP

用AspectJ注解声明切面

切面:带有@Aspect注解的Java类

通知:是标注有以下5种注解的简单的Java方法

@Before:前置通知,在方法执行之前执行

@After:后置通知,在方法执行之后执行

@AfterReturning:返回通知,在方法返回结果之后执行

@AfterThrowing:异常通知,在方法抛出异常之后 @Around:环绕通知,围绕着方法执行

前置后置通知

前置通知:在方法执行之前执行的通知

前置通知使用: @Before , @After注解,并将切入点表达式的值作为注解值。

利用方法签名编写AspectJ切入点表达式

最典型的切入点表达式是根据方法的签名来匹配各种方法:


指定切面的优先级

指定切面的优先级:

在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。

切面的优先级可以通过实现Ordered接口或利用@Order注解指定。

实现Ordered接口,getOrder()方法的返回值越小,优先级越高。

若使用@Order注解,序号出现在注解中。

  1. @Aspect
  2. @Order(0)
  3. public class CalculaotorValidationAspect
  4. @Aspect
  5. @Order(1)
  6. public class CalculatorLoggingAspect

基于XML的配置声明切面

基于XML声明切面:

当使用XML声明切面时,需要在<beans>根元素中导入aop Schema

在Bean配置文件中,所有的Spring AOP配置都必须定义在<aop:config>元素内部。对于每个切面而言,都要创建一个<aop:aspect>元素来为具体的切面实现引用后端Bean实例。

使用<aop:pointcut>来配置切点,通知元素需要用<aop:before>等元素,method属性指定切面类中通知方法的名称。


Spring实例练习

了解了这些Spring的概念知识后,必须要有一个好的例子来理解,下面就以一个简单的小例子来举例子说明。

定义一个实体类User,实现它属性的set,get方法:

  1. public class User {
  2. private int id;
  3. private String uname;
  4. private String pwd;
  5. private int score;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public String getUname() {
  13. return uname;
  14. }
  15. public void setUname(String uname) {
  16. this.uname = uname;
  17. }
  18. public String getPwd() {
  19. return pwd;
  20. }
  21. public void setPwd(String pwd) {
  22. this.pwd = pwd;
  23. }
  24. public int getScore() {
  25. return score;
  26. }
  27. public void setScore(int score) {
  28. this.score = score;
  29. }
  30. }

定义一个接口ScoreService,接口中定义一个登陆方法:

  1. import com.jredu.aop.entity.User;
  2. public interface ScoreService {
  3. /**
  4. * 登录
  5. * @param user
  6. * @return
  7. */
  8. User login(User user);
  9. }

定义一个类ScoreServiceImpl,实现ScoreService 接口中的方法:

  1. import org.springframework.stereotype.Component;
  2. import com.jredu.aop.entity.User;
  3. import com.jredu.aop.service.ScoreService;
  4. @Component("score")
  5. public class ScoreServiceImpl implements ScoreService{
  6. /**
  7. * 登录
  8. */
  9. @Override
  10. public User login(User user) {
  11. // TODO Auto-generated method stub
  12. System.out.println("登录成功!");
  13. return user;
  14. }
  15. }

在applicationContext-aop2.xml中依赖注入user,并配置扫描,配置切面等。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:context="http://www.springframework.org/schema/context"
  7. xmlns:mvc="http://www.springframework.org/schema/mvc"
  8. xmlns:util="http://www.springframework.org/schema/util"
  9. xsi:schemaLocation="http://www.springframework.org/schema/beans
  10. http://www.springframework.org/schema/beans/spring-beans.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context.xsd
  13. http://www.springframework.org/schema/util
  14. http://www.springframework.org/schema/util/spring-util.xsd
  15. http://www.springframework.org/schema/aop
  16. http://www.springframework.org/schema/aop/spring-aop.xsd
  17. http://www.springframework.org/schema/mvc
  18. http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  19. <!-- 自动扫描标签 -->
  20. <context:component-scan base-package="com.jredu.aop">
  21. </context:component-scan>
  22. <bean
  23. id="user" class="com.jredu.aop.entity.User"
  24. p:id="1"
  25. p:uname="张三"
  26. p:pwd="123456"
  27. p:score="0"
  28. />
  29. <bean
  30. id="springAspect" class="com.jredu.aop.aspect.SpringAspect"
  31. />
  32. <!-- 配置切面 -->
  33. <aop:config>
  34. <!-- 配置切点 -->
  35. <aop:pointcut expression="execution(* com.jredu.aop.service.ScoreService.login(..))" id="pointcut"/>
  36. <!-- 配置切面 -->
  37. <aop:aspect ref="springAspect">
  38. <aop:around method="around" pointcut-ref="pointcut"/>
  39. <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="obj"/>
  40. </aop:aspect>
  41. </aop:config>
  42. </beans>

定义切面类SpringAspect,在切面中定义相关方法。

  1. import org.aspectj.lang.JoinPoint;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import com.jredu.aop.entity.User;
  4. public class SpringAspect {
  5. /**
  6. * 执行前
  7. * @param point
  8. *//*
  9. public void before(JoinPoint point){
  10. String method = point.getSignature().getName();
  11. System.out.println("before method:"+method);
  12. }*/
  13. /**
  14. * 执行后
  15. * @param point
  16. * @throws Throwable
  17. */
  18. public User around(ProceedingJoinPoint point) throws Throwable{
  19. String method = point.getSignature().getName();
  20. System.out.println("before method:"+method);
  21. //调用目标方法前
  22. User user = (User) point.proceed();
  23. //调用目标方法后
  24. System.out.println("原来的用户积分:"+user.getScore());
  25. System.out.println("after method:"+method);
  26. user.setScore(user.getScore()+100);
  27. return user;
  28. }
  29. /**
  30. * 最终返回结果
  31. * @param point
  32. * @param obj
  33. */
  34. public void afterReturning(JoinPoint point,Object obj){
  35. String method = point.getSignature().getName();
  36. System.out.println("afterReturning method:"+method);
  37. User user = (User) obj;
  38. System.out.println("现在用户的积分:"+user.getScore());
  39. }
  40. }

测试类:

  1. import org.springframework.context.ApplicationContext;
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;
  3. import com.jredu.aop.entity.User;
  4. import com.jredu.aop.service.ScoreService;
  5. public class ScoreTest {
  6. public static void main(String[] args) {
  7. ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-aop2.xml");
  8. User user = (User) app.getBean("user");
  9. ScoreService service =(ScoreService) app.getBean("score");
  10. service.login(user);
  11. }
  12. }

项目完成后的项目截图:

Spring框架——AOP面向切面编程的更多相关文章

  1. Spring框架 AOP面向切面编程(转)

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  2. 详解Spring框架AOP(面向切面编程)

    最近在学习AOP,之前一直很不明白,什么是AOP?为什么要使用AOP,它有什么作用?学完之后有一点小小的感触和自己的理解,所以在这里呢就跟大家一起分享一下 AOP(Aspect-Oriented Pr ...

  3. Spring 08: AOP面向切面编程 + 手写AOP框架

    核心解读 AOP:Aspect Oriented Programming,面向切面编程 核心1:将公共的,通用的,重复的代码单独开发,在需要时反织回去 核心2:面向接口编程,即设置接口类型的变量,传入 ...

  4. Spring:AOP面向切面编程

    AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...

  5. 03-spring框架—— AOP 面向切面编程

    3.1 动态代理 动态代理是指,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(不是真实定义的类)在程序运行时由 JVM 根据反射等机制动态生成的.代理对象与目标 ...

  6. spring:AOP面向切面编程02

    参考: https://blog.csdn.net/jeffleo/article/details/54136904 一.AOP的核心概念AOP(Aspect Oriented Programming ...

  7. Spring的AOP面向切面编程

    什么是AOP? 1.AOP概念介绍 所谓AOP,即Aspect orientied program,就是面向方面(切面)的编程. 功能: 让关注点代码与业务代码分离! 关注点: 重复代码就叫做关注点: ...

  8. Spring注解 - AOP 面向切面编程

    基本概念: AOP:Aspect Oriented Programming,即面向切面编程 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式 前置通知(@Before):在目标 ...

  9. JavaWeb_(Spring框架)SpringAOP面向切面编程

    SpringAOP:面向切面编程(面向fifter编程) 通俗易懂术语:所有纵向重复的代码,我们提取成横向的代码 以下文章内容参考知乎:从0带你学习SpringAOP,彻底的理解AOP思想 传送门 1 ...

随机推荐

  1. SSM框架实现多张图片和其他数据一起上传

    一.SSM+Form 多张图片和其他数据一起上传, 1.导包: commons-fileupload-1.3.3.jar commons-io-2.4.jar 2.springmvc.xml 文件配置 ...

  2. 用Margin还是用Padding的区别

    用margin还是用padding这个问题是每个学习CSS进阶时的必经之路. CSS边距属性定义元素周围的空间.通过使用单独的属性,可以对上.右.下.左的外边距进行设置.也可以使用简写的外边距属性同时 ...

  3. 2.1JAVA文件基本结构

    命名 包名 全为英文小写 项目包命名 域名反转.团队名.项目名 相关项目包命名 域名反转.团队名.父项目名.子项目名 类和接口名 所有单词首字母大写 抽象类 用"Abstract" ...

  4. SpringSecurity配置文件

    @EnableWebSecurity public class seccurityConfig extends WebSecurityConfigurerAdapter { @Override pro ...

  5. 感谢 Gridea,让我有动力写作

    1. 真的要感谢 Gridea,让我对写作产生热忱.一直有在各大博客平台输出的习惯,但是都没有持续更新.有的平台广告太多,写不下去.有的平台排版复杂,写文章1个小时,排版要2个小时.所以后面换成了静态 ...

  6. 接口的不同写法在Swagger上的不同

    接口请求方法类型 (1) 如果接口没有指定请求的 method 类型,例如 GET.POST.PUT.DELETE 等. Swagger中 (2)指定了请求方法后 Swagger中就只有一个GET请求 ...

  7. log4net配置及使用

    log4net简介 log4net库是Apache log4j框架在Microsoft.NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台.文件.数据库等)的工具. log4net详解 ...

  8. 剑指offer 面试题10.1:青蛙跳台阶

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 编程思想 对于本题,前提只有 一次 1阶或者2阶的跳法.a.如果两种跳 ...

  9. 转载 - Ubuntu源改国内源 与 批量更改ubuntu机器apt源

    change_apt_source.sh # !/bin/bash # 备份原来的源文件 cp /etc/apt/sources.list /etc/apt/sources.list.bak # 获取 ...

  10. python模块详解 | pyquery

    简介 pyquery是一个强大的 HTML 解析库,利用它,我们可以直接解析 DOM 节点的结构,并通过 DOM 节点的一些属性快速进行内容提取. 官方文档:http://pyquery.readth ...