Spring框架——AOP面向切面编程
简介
AOP(面向切面编程):是一种新的方法论,是对传统OOP(面向对象编程)的补充。
AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里。
AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级。
业务模块更简洁,只包含核心业务的代码。
横切关注点:
AOP练习
Aop关于加减乘除的练习:
定义一个算法接口,含有4个方法,加减乘除。
public interface ArithmeticCalculator(){
//加
double add(double a,double b);
//减
double sub(double a,double b);
//乘
double mul(double a,double b);
//除
double div(double a,double b);
}
Aop思想:
public void before(double a ,double b){
System.out.println(a+"and"+b);
}
public void after(result){
System.out.println("结果是"+result);
}
public double sub(double a, double b){
before(a,b);
double result=a+b;
after(result);
return result;
}
但是,这样做是有一些弊端存在的,比如:
代码混乱:
越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
代码分散:
以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有模块。
那么,如何解决这些问题呢?
这就需要使用Spring的动态代理模式来完成了。
使用动态代理解决问题
代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理取代原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
Spring AOP
用AspectJ注解声明切面
切面:带有@Aspect注解的Java类
通知:是标注有以下5种注解的简单的Java方法
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行
@AfterReturning:返回通知,在方法返回结果之后执行
@AfterThrowing:异常通知,在方法抛出异常之后 @Around:环绕通知,围绕着方法执行
前置后置通知
前置通知:在方法执行之前执行的通知
前置通知使用: @Before , @After注解,并将切入点表达式的值作为注解值。
利用方法签名编写AspectJ切入点表达式
最典型的切入点表达式是根据方法的签名来匹配各种方法:
指定切面的优先级
指定切面的优先级:
在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。
切面的优先级可以通过实现Ordered接口或利用@Order注解指定。
实现Ordered接口,getOrder()方法的返回值越小,优先级越高。
若使用@Order注解,序号出现在注解中。
@Aspect
@Order(0)
public class CalculaotorValidationAspect
@Aspect
@Order(1)
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方法:
public class User {
private int id;
private String uname;
private String pwd;
private int score;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
定义一个接口ScoreService,接口中定义一个登陆方法:
import com.jredu.aop.entity.User;
public interface ScoreService {
/**
* 登录
* @param user
* @return
*/
User login(User user);
}
定义一个类ScoreServiceImpl,实现ScoreService 接口中的方法:
import org.springframework.stereotype.Component;
import com.jredu.aop.entity.User;
import com.jredu.aop.service.ScoreService;
@Component("score")
public class ScoreServiceImpl implements ScoreService{
/**
* 登录
*/
@Override
public User login(User user) {
// TODO Auto-generated method stub
System.out.println("登录成功!");
return user;
}
}
在applicationContext-aop2.xml中依赖注入user,并配置扫描,配置切面等。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描标签 -->
<context:component-scan base-package="com.jredu.aop">
</context:component-scan>
<bean
id="user" class="com.jredu.aop.entity.User"
p:id="1"
p:uname="张三"
p:pwd="123456"
p:score="0"
/>
<bean
id="springAspect" class="com.jredu.aop.aspect.SpringAspect"
/>
<!-- 配置切面 -->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut expression="execution(* com.jredu.aop.service.ScoreService.login(..))" id="pointcut"/>
<!-- 配置切面 -->
<aop:aspect ref="springAspect">
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="obj"/>
</aop:aspect>
</aop:config>
</beans>
定义切面类SpringAspect,在切面中定义相关方法。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import com.jredu.aop.entity.User;
public class SpringAspect {
/**
* 执行前
* @param point
*//*
public void before(JoinPoint point){
String method = point.getSignature().getName();
System.out.println("before method:"+method);
}*/
/**
* 执行后
* @param point
* @throws Throwable
*/
public User around(ProceedingJoinPoint point) throws Throwable{
String method = point.getSignature().getName();
System.out.println("before method:"+method);
//调用目标方法前
User user = (User) point.proceed();
//调用目标方法后
System.out.println("原来的用户积分:"+user.getScore());
System.out.println("after method:"+method);
user.setScore(user.getScore()+100);
return user;
}
/**
* 最终返回结果
* @param point
* @param obj
*/
public void afterReturning(JoinPoint point,Object obj){
String method = point.getSignature().getName();
System.out.println("afterReturning method:"+method);
User user = (User) obj;
System.out.println("现在用户的积分:"+user.getScore());
}
}
测试类:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jredu.aop.entity.User;
import com.jredu.aop.service.ScoreService;
public class ScoreTest {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-aop2.xml");
User user = (User) app.getBean("user");
ScoreService service =(ScoreService) app.getBean("score");
service.login(user);
}
}
项目完成后的项目截图:
Spring框架——AOP面向切面编程的更多相关文章
- Spring框架 AOP面向切面编程(转)
一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...
- 详解Spring框架AOP(面向切面编程)
最近在学习AOP,之前一直很不明白,什么是AOP?为什么要使用AOP,它有什么作用?学完之后有一点小小的感触和自己的理解,所以在这里呢就跟大家一起分享一下 AOP(Aspect-Oriented Pr ...
- Spring 08: AOP面向切面编程 + 手写AOP框架
核心解读 AOP:Aspect Oriented Programming,面向切面编程 核心1:将公共的,通用的,重复的代码单独开发,在需要时反织回去 核心2:面向接口编程,即设置接口类型的变量,传入 ...
- Spring:AOP面向切面编程
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...
- 03-spring框架—— AOP 面向切面编程
3.1 动态代理 动态代理是指,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(不是真实定义的类)在程序运行时由 JVM 根据反射等机制动态生成的.代理对象与目标 ...
- spring:AOP面向切面编程02
参考: https://blog.csdn.net/jeffleo/article/details/54136904 一.AOP的核心概念AOP(Aspect Oriented Programming ...
- Spring的AOP面向切面编程
什么是AOP? 1.AOP概念介绍 所谓AOP,即Aspect orientied program,就是面向方面(切面)的编程. 功能: 让关注点代码与业务代码分离! 关注点: 重复代码就叫做关注点: ...
- Spring注解 - AOP 面向切面编程
基本概念: AOP:Aspect Oriented Programming,即面向切面编程 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式 前置通知(@Before):在目标 ...
- JavaWeb_(Spring框架)SpringAOP面向切面编程
SpringAOP:面向切面编程(面向fifter编程) 通俗易懂术语:所有纵向重复的代码,我们提取成横向的代码 以下文章内容参考知乎:从0带你学习SpringAOP,彻底的理解AOP思想 传送门 1 ...
随机推荐
- Java学习日报7.9
今日内容 阅读了构建之法第一章 工程师的宗旨:我构建,故我在. 哲学家的宗旨:我思,故我在. 科学家的宗旨:我发现故我在. 明天继续研究构建之法这本书!
- TurtleBot3使用课程-第二节b(北京智能佳)
目录 1.导航 2 1.1 运行导航节点 3 1.1.1 [远程PC]运行roscore 3 1.1.2 [turtlebot3 SBC]运行提出turtlebot3 3 1.1.3[远程PC]运行导 ...
- shell脚本学习之6小时搞定(1)
shell脚本学习之6小时搞定(1) 简介 Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本. Unix/Linux上常见的Shell脚本解释器有bash.sh.csh.ksh等,习惯上把 ...
- express安装问题
步骤1 npm install -g express(全局安装express) (安装node就不必说了) 步骤2 npm install -g express-generator(安装命令工具) 完 ...
- 设计模式之委派模式(Delegate Pattern)深入浅出
学习目标:精简程序逻辑,提升代码的可读性. 内容定位:希望通过对委派模式的学习,让自己写出更加优雅的代码的人群. 委派模式定义: 委派模式(Delegate Pattern)的基本作用是负责任务的调度 ...
- “500 oops socket” Debian 9 running via Linux Deploy上成功部署vsftpd的解决方案(201901原创)【成功完美简单极致】
"500 oops socket" Debian 9 running via Linux Deploy上成功部署vsftpd的解决方案(201901原创)[成功完美简单极致] #自 ...
- Spark推荐系统实践
推荐系统是根据用户的行为.兴趣等特征,将用户感兴趣的信息.产品等推荐给用户的系统,它的出现主要是为了解决信息过载和用户无明确需求的问题,根据划分标准的不同,又分很多种类别: 根据目标用户的不同,可划分 ...
- 常用 .gitignore 模板
前言 每次建项目的时候可以直接复制了,也算是方便自己,以后发现少的会更新 正文 作用 git提交时忽略文件 文件名 .gitignore Python # Byte-compiled / optimi ...
- 【Flutter】功能型组件之数据共享
前言 InheritedWidget提供了一种数据在widget树中从上到下传递.共享的方式,例如在应用的根widget中通过InheritedWidget共享了一个数据,那么便可以在子widge ...
- 在阿里云托管的k8s上使用nas做动态存储
前言 关于aliyun托管k8s的存储插件主要有两种: CSI # kubectl get pod -n kube-system | grep csi-plugin csi-plugin-8bbnw ...