spring框架中的aop_spring三大核心

spring框架中的aop_spring三大核心spring框架 AOP核心详解

大家好,又见面了,我是你们的朋友全栈君。

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

一 AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

二 Spring AOP

Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

三 基于注解的AOP配置方式

1.启用@AsjectJ支持

在applicationContext.xml中配置下面一句:

 
<aop:aspectj-autoproxy /> 

2.通知类型介绍

(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可

(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值

(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名

来访问目标方法中所抛出的异常对象

(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式

(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

3.例子:

6e30ba1aa32b4962a9713f3e1f6414ef

 

(1)Operator.java –> 切面类

 
@Component @Aspect public class Operator { @Pointcut("execution(* com.aijava.springcode.service..*.*(..))") public void pointCut(){} @Before("pointCut()") public void doBefore(JoinPoint joinPoint){ System.out.println("AOP Before Advice..."); } @After("pointCut()") public void doAfter(JoinPoint joinPoint){ System.out.println("AOP After Advice..."); } @AfterReturning(pointcut="pointCut()",returning="returnVal") public void afterReturn(JoinPoint joinPoint,Object returnVal){ System.out.println("AOP AfterReturning Advice:" + returnVal); } @AfterThrowing(pointcut="pointCut()",throwing="error") public void afterThrowing(JoinPoint joinPoint,Throwable error){ System.out.println("AOP AfterThrowing Advice..." + error); System.out.println("AfterThrowing..."); } @Around("pointCut()") public void around(ProceedingJoinPoint pjp){ System.out.println("AOP Aronud before..."); try { pjp.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("AOP Aronud after..."); } } 

(2)UserService.java –> 定义一些目标方法

 
@Service public class UserService { public void add(){ System.out.println("UserService add()"); } public boolean delete(){ System.out.println("UserService delete()"); return true; } public void edit(){ System.out.println("UserService edit()"); int i = 5/0; } } 

(3).applicationContext.xml

 
<context:component-scan base-package="com.aijava.springcode"/> <aop:aspectj-autoproxy /> 

(4).Test.java

 
public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); UserService userService = (UserService) ctx.getBean("userService"); userService.add(); } } 

上面是一个比较简单的测试,基本涵盖了各种增强定义。注意:做环绕通知的时候,调用ProceedingJoinPoint的proceed()方法才会执行目标方法。

4.通知执行的优先级

进入目标方法时,先织入Around,再织入Before,退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。

注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!同时使用也没啥意义。

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

5.切入点的定义和表达式

切入点表达式的定义算是整个AOP中的核心,有一套自己的规范

Spring AOP支持的切入点指示符:

(1)execution:用来匹配执行方法的连接点

A:@Pointcut(“execution(* com.aijava.springcode.service..*.*(..))”)

第一个*表示匹配任意的方法返回值,..(两个点)表示零个或多个,上面的第一个..表示service包及其子包,第二个*表示所有类,第三个*表示所有方法,第二个..表示

方法的任意参数个数

B:@Pointcut(“within(com.aijava.springcode.service.*)”)

within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点

C:@Pointcut(“this(com.aijava.springcode.service.UserService)”)

this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService

D:@Pointcut(“bean(userService)”)

bean也是非常常用的,bean可以指定IOC容器中的bean的名称

后言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别:

1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知 是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。

2) 环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用

6.基于XML形式的配置方式

开发中如果选用XML配置方式,通常就是POJO+XML来开发AOP,大同小异,无非就是在XML文件中写切入点表达式和通知类型

例子:

(1)Log.java

 
public class Log { private Integer id; //操作名称,方法名 private String operName; //操作人 private String operator; //操作参数 private String operParams; //操作结果 成功/失败 private String operResult; //结果消息 private String resultMsg; //操作时间 private Date operTime = new Date(); setter,getter } 

(2).Logger.java

 
/** * 日志记录器 (AOP日志通知) */ public class Logger { @Resource private LogService logService; public Object record(ProceedingJoinPoint pjp){ Log log = new Log(); try { log.setOperator("admin"); String mname = pjp.getSignature().getName(); log.setOperName(mname); //方法参数,本例中是User user Object[] args = pjp.getArgs(); log.setOperParams(Arrays.toString(args)); //执行目标方法,返回的是目标方法的返回值,本例中 void Object obj = pjp.proceed(); if(obj != null){ log.setResultMsg(obj.toString()); }else{ log.setResultMsg(null); } log.setOperResult("success"); log.setOperTime(new Date()); return obj; } catch (Throwable e) { log.setOperResult("failure"); log.setResultMsg(e.getMessage()); } finally{ logService.saveLog(log); } return null; } } 

(3).applicationContext.xml

 
<aop:config> <aop:aspect id="loggerAspect" ref="logger"> <aop:around method="record" pointcut="(execution(* com.aijava.distributed.ssh.service..*.add*(..)) or execution(* com.aijava.distributed.ssh.service..*.update*(..)) or execution(* com.aijava.distributed.ssh.service..*.delete*(..))) and !bean(logService)"/> </aop:aspect> </aop:config> 

注意切入点表达式,!bean(logService) 做日志通知的时候,不要给日志本身做日志,否则会造成无限循环!

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

有关更详细的Spring AOP知识,可以查看Spring官方文档第9章Aspect Oriented Programming with Spring

7.JDK动态代理介绍

例子:

(1)UserService.java

 
public interface UserService { public void add(); } 

(2)UserServiceImpl.java

 
public class UserServiceImpl implements UserService{ public void add() { System.out.println("User add()..."); } } 

(3)ProxyUtils.java

 
public class ProxyUtils implements InvocationHandler{ private Object target; public ProxyUtils(Object target){ this.target = target; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do sth before..."); method.invoke(target, args); System.out.println("do sth after..."); return null; } } 

(4)Test.java

 
public class Test { public static void main(String[] args) { UserService userService = new UserServiceImpl(); ProxyUtils proxyUtils = new ProxyUtils(userService); UserService proxyObject = (UserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),UserServiceImpl.class.getInterfaces(), proxyUtils); proxyObject.add(); } } 

JDK动态代理核心还是一个InvocationHandler,记住这个就行了。

转载于:https://my.oschina.net/u/3990817/blog/2990889

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/107133.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 谷尼GoonieFilter网站内容敏感词过滤系统[通俗易懂]

    谷尼GoonieFilter网站内容敏感词过滤系统[通俗易懂] GoonieFilter网站内容敏感词过滤系统 GoonieFilter网站内容敏感词过滤系统是一套基于多智能主体技术的网站内容敏感词过滤系统,引入了多个主体来实现敏感信息过滤功能,通过多主体的协作,可以有效的对网站敏感信息的采集、处理和监控,以计算机智能处理技术辅助信息汇集整理和分析,最后去伪存真,实现网站敏感信息过滤。GoonieFilter敏感词过滤系统适用于网站新闻、博客…

  • Visio 2013 Professional专业版密钥

    Visio 2013 Professional专业版密钥Visio2013产品密钥分享,在安装时可以使用以下密钥:C2FG9-N6J68-H8BTJ-BW3QX-RM3B32NYF6-QG2CY-9F8XC-GWMBW-29VV8FJ2N7-W8TXC-JB8KB-DCQ7Q-7T7V3VXX6C-DN3HQ-3CRXG-RF4KT-YG7V3B3C7Q-D6NH2-2VRFW-HHWDG-FVQB6TCWJK-N6GFH-8…

  • [MicroPython]TurniBit开发板DIY自动窗帘模拟系统

    [MicroPython]TurniBit开发板DIY自动窗帘模拟系统一、准备工作üTurnipBit开发板一块ü下载数据线一条ü微型步进电机(28BYJ-48)一个ü步进电机驱动板(ULN2003APG)一块ü光敏传感器一个üTurnipBit扩展板一块ü接入网络的电脑一台ü在线可视化编程器<http://turnipbit.com/PythonEditor/edit…

  • matlab中dde23函数_时滞模型的matlab编程

    matlab中dde23函数_时滞模型的matlab编程ddex1histz=@(t)2*ones(2,1);ddex1dez=@(t,y,Z)[y(1)*(1+0.1*sin(t)-0.1*Z(1,1)-y(2)/(1+y(1)));    y(2)*((2+sin(t))*10^(-5)+9*Z(1,2)/(1+Z(1,2))-Z(2,1))]; sol=dde23(ddex1dez

  • Oracle下查看索引的语句

    Oracle下查看索引的语句1.查询一张表里面索引select*fromuser_indexeswheretable_name=upper(‘表名’);2.查询被索引字段select*fromuser_ind_columnswhereindex_name=(‘索引名称’);3.给某一字段创建索引createindex索引名on表名(字段);…

  • Python安装scrapy库

    Python安装scrapy库由于本人在安装scrapy库的道路上遇到过很多坑,由此不能再坐视不管,来帮帮广大同胞首先在此网站https://www.lfd.uci.edu/~gohlke/pythonlibs/找到twisted库:在此中间找适合自己电脑配置的文件twisted下载然后用命令行进入此目录然后再命令行执行pipinstall+"你所下载的那个文件名"+"(注意这里有个点).wh…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号