spring aop简单理解
aop原理是spring帮我们封装了动态代理,然后我们只管写具体的业务,我们将公共业务也写到具体的一个类中并实现spring为我们提供的对应要连接切入哪个位置的接口,然后再xml中配置它们的关系即可。
优点:和动态代理一样,具体实现只管具体实现使的代码更加纯粹,公共业务只需实现自己对应的接口,然后编码即可,有了动态代理的好处,又没有手写动态代理那么复杂,这就是aop(被分装后的动态代理)。
一:实现spring接口的方式
1.UserService接口:
package mr.li.service; public interface UserService { void add(); void remove(); }
2.UserServiceImpl实现类:
package mr.li.service.impl; import mr.li.service.UserService; public class UserServiceImpl implements UserService{ @Override
public void add() {
System.out.println("添加一条数据");
} @Override
public void remove() {
System.out.println("删除一条数据");
} }
3.前置通知:Log日志打印
package mr.li.log; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice;
/**
* 前置切面:日志打印
* @author yanLong.Li
* @date 2019年3月16日 下午10:33:22
*/
public class Log implements MethodBeforeAdvice{ @Override
public void before(Method method, Object[] arg1, Object target) throws Throwable {
System.out.println("aop前置:"+target.getClass().getName()+"类的"+ method + "方法执行了~~");
} }
4后置通知:AfterLog 日志打印
package mr.li.log; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice;
/**
* 后置切面:日志打印
* @author yanLong.Li
* @date 2019年3月16日 下午10:33:44
*/
public class AfterLog implements AfterReturningAdvice{ @Override
public void afterReturning(Object result, Method method, Object[] arg2, Object target) throws Throwable {
System.out.println("aop后置:"+target.getClass().getName()+"类的"+ method + "方法执行了,返回结果为"+result);
}
}
5.xml关系配置
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="mr.li.service.impl.UserServiceImpl"/>
<bean id = "log" class="mr.li.log.Log"/>
<bean id = "afterLog" class="mr.li.log.AfterLog"/>
<aop:config>
<!-- 配置被切入的哪个类使用 execution表达式第一个:“*”表示返回值 第二个*表示所有的 ..标识所有的参数 -->
<aop:pointcut expression="execution(* mr.li.service.impl.UserServiceImpl.*(..))" id="aoop"/>
<!-- 设置要切入的类:-->
<aop:advisor advice-ref="log" pointcut-ref="aoop"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="aoop"/>
</aop:config>
</beans>
6.测试类
package mr.li.client; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import mr.li.service.UserService; public class Client { public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.remove();
userService.add();
}
}
打印结果:
aop前置:mr.li.service.impl.UserServiceImpl类的public abstract void mr.li.service.UserService.remove()方法执行了~~
删除一条数据
aop后置:mr.li.service.impl.UserServiceImpl类的public abstract void mr.li.service.UserService.remove()方法执行了,返回结果为null
aop前置:mr.li.service.impl.UserServiceImpl类的public abstract void mr.li.service.UserService.add()方法执行了~~
添加一条数据
aop后置:mr.li.service.impl.UserServiceImpl类的public abstract void mr.li.service.UserService.add()方法执行了,返回结果为null
二:自定义aop,切面不在需要实现接口,自己写即可,只是调整下配置
1.UserService:和上面一样
2.UserServiceImpl:和上面一样
3.Log切面
package mr.li.log; /**
* 前置切面:日志打印
* @author yanLong.Li
* @date 2019年3月16日 下午10:33:22
*/
public class Log { public void before() {
System.out.println("前置通知");
} public void after() {
System.out.println("后置通知");
} }
4.xml配置
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="mr.li.service.impl.UserServiceImpl"/>
<bean id = "log" class="mr.li.log.Log"/>
<aop:config>
<aop:aspect ref="log">
<!-- 配置被切入的哪个类使用 execution表达式 *表示所有的 ..标识所有的参数 -->
<aop:pointcut expression="execution(* mr.li.service.impl.UserServiceImpl.*(..))" id="pointcut"/>
<!-- 配置前置通知 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 配置后置通知 -->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
5.测试
package mr.li.client; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import mr.li.service.UserService; public class Client { public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.remove();
userService.add();
}
}
打印结果:
前置通知
删除一条数据
后置通知
前置通知
添加一条数据
后置通知
三:注解的方式:注意下环绕通知,参数说明,以及使用(proceedingJoinpoint在下面有额外解释)
1.UserService:和最上面一样
2.UserServiceImpl:和最上面一样
3.切面:Log
package mr.li.log; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; /**
* 切面:日志打印
* @author yanLong.Li
* @date 2019年3月16日 下午10:33:22
*/
@Aspect
public class Log { /**
* 前置通知:execution表示切入点
*/
@Before("execution(* mr.li.service.impl.UserServiceImpl.*(..))")
public void before() {
System.out.println("注解:前置通知");
} /**
* 后置通知
*/
@After("execution(* mr.li.service.impl.UserServiceImpl.*(..))")
public void after() {
System.out.println("注解:后置通知");
} /**
* 环绕通知
* @param jp 此参数是spring给我们的,它里面可以干很多事,包括继续执行被切面的方法,拿到方法签名,他会在被切面的方法之前运作
* @throws Throwable
*/
@Around("execution(* mr.li.service.impl.UserServiceImpl.*(..))")
public Object aroud(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("方法签名:"+jp.getSignature());
//执行此方法
Object result = jp.proceed();
System.out.println("环绕后");
return result;
}
}
4.xml配置
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="mr.li.service.impl.UserServiceImpl"/>
<bean id = "log" class="mr.li.log.Log"/>
<!-- 此配置会自动去找aop配置 -->
<aop:aspectj-autoproxy/>
</beans>
5.测试:
package mr.li.client; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import mr.li.service.UserService; public class Client { public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.remove();
userService.add();
}
}
打印结果:
注解:前置通知
删除一条数据
环绕后
注解:后置通知
环绕前
方法签名:void mr.li.service.UserService.add()
注解:前置通知
添加一条数据
环绕后
注解:后置通知
额外对ProceedingJoinPoint参数的描述
package com.qty.arena.util; import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; import com.qty.arena.helper.MessagePushHelper;
import com.qty.database.dto.arena.match.SyncAll; /**
* 在被@NotDuplicate注解所标注的方法上,过滤请求者重复请求的消息
* @author yanLong.Li
* @date 2019年2月11日 上午11:11:01
*/
@Aspect
@Component
public class NotDuplicateAop { // private static final Set<String> KEY = new ConcurrentSkipListSet<>(); private static final Set<Long> KEY = new ConcurrentSkipListSet<>(); @Pointcut("@annotation(com.qty.arena.util.NotDuplicate)")
public void duplicate() {} /**
* 对方法拦截后进行参数验证
* @param pjp
* @return
* @throws Throwable
*/
@Around("duplicate()")
public Object duplicate(ProceedingJoinPoint pjp) throws Throwable{
Object[] objs = pjp.getArgs();
Long dbId = null;
if(objs[0] instanceof Long) {
dbId = (Long)objs[0];
}
if(dbId == null) {
throw new NumberFormatException("在解析请求的dbId时发生异常,数字不能解析,值:"+objs[0]);
}
boolean success = KEY.add(dbId);
if(!success){
MessagePushHelper.getInstance().pushSingleMessage(dbId, SyncAll.valueOf("频繁操作,请稍后再试"));
return null;
}
try {
//方法执行前
return pjp.proceed();
} finally {
//方法执行后
KEY.remove(dbId);
}
}
spring aop简单理解的更多相关文章
- Spring AOP 简单理解
AOP技术即(面向切面编程)技术是在面向对象编程基础上的发展,AOP技术是对所有对象或一类对象编程.核心是在不增加代码的基础上,还增加了新的功能.AOP编程在开发框架本身用的比较多,而实际项目中,用的 ...
- Spring AOP深入理解之拦截器调用
Spring AOP深入理解之拦截器调用 Spring AOP代理对象生成回想 上一篇博客中:深入理解Spring AOP之二代理对象生成介绍了Spring代理对象是怎样生成的,当中重点介绍了JDK动 ...
- Spring Aop(二)——基于Aspectj注解的Spring Aop简单实现
转发地址:https://www.iteye.com/blog/elim-2394762 2 基于Aspectj注解的Spring Aop简单实现 Spring Aop是基于Aop框架Aspectj实 ...
- Spring Aop的理解和简单实现
1.AOP概念 所说的面向切面编程其实就是在处理一系列业务逻辑的时候这一系列动作看成一个动作集合.比如连接数据库来说: 加载驱动-----获取class--------获取连接对象-------访问数 ...
- Spring AOP 简单入门笔记 (转)
分享一个自己写的最为简单的Spring AOP的应用,其实,本人也是学习Spring不久,只是把一些个人的理解分享下,供参考.可能很多人刚开始不太理解到底啥是AOP,其实它也是相对 OOP来说的,类似 ...
- Spring aop 简单示例
简单的记录一下spring aop的一个示例 基于两种配置方式: 基于xml配置 基于注解配置 这个例子是模拟对数据库的更改操作添加事物 其实并没有添加,只是简单的输出了一下记录 首先看下整个例子的目 ...
- spring aop 的理解
spring aop的相关概念(所有的概念都是为了生成代理类这个过程所需要的信息的抽象): 1.Targer:目标对象.被代理的对象. 2.Advice:增强/通知.就是为目标对象扩展的功能.分为前置 ...
- Spring的AOP简单理解
最近在研究spring的AOP,翻译出来的意思是面向切面. 总结如下: 所谓AOP就是将分散在各个方法处的公共代码提取到一处, 并通过类似拦截器的机制实现代码的动态整合.可以简单地想象成, 在某个方法 ...
- spring AOP简单入门
AOP(aspect oriented programming)面向切面编程. 大致意思是在方法的执行过程中织入其他要执行的方法. 项目结构图 先介绍一下通过代理的方式实现aop,几个文件和上一篇一样 ...
随机推荐
- 【shell】查找后拷贝find . -name *.csv -exec cp {} /home/ \;
Find命令的一般形式为: find pathname -options [-print -exec -ok] 让我们来看看该命令的参数: pathname: find命令所查找的目录路径.例如用.来 ...
- H3C SNMP OID
有两种mib-style [1]老些的设备 cpu 使用率OID: .1.3.6.1.4.1.25506.2.6.1.1.1.1.6.slot 内存使用率OID: .1.3.6.1.4.1.2550 ...
- KVM -> 虚拟机在线热添加技术_04
热添加技术 1.KVM在线热添加硬盘
- 批量监测dns是否可用脚本,不可用时并切换
#!/usr/bin/env python # coding=utf-8 # hexm@2016-02-14 import time import requests import paramiko i ...
- Maven介绍及安装与配置
一.Maven的作用 在开发中,为了保证编译通过,我们会到处去寻找jar包,当编译通过了,运行的时候,却发现"ClassNotFoundException",我们想到的是,难道还差 ...
- PYTHON-模块time&datetime+ 目录规范
1.目录规范 ***** (1)文件夹的规范写法 bin 可执行文件 conf 配置文件 core 主要业务逻辑 db 数据文件 lib 库 (公共代码 第三方模块) log 日志文件 readme ...
- Golang依赖管理工具:glide从入门到精通使用
这是一个创建于 2017-07-22 05:33:09 的文章,其中的信息可能已经有所发展或是发生改变. 介绍 不论是开发Java还是你正在学习的Golang,都会遇到依赖管理问题.Java有牛逼轰轰 ...
- NodeJs>------->>第一章:Node.js介绍
一:章节前言 二:Node.js概述 1:使用node.js能够解决什么问题 2:实现高性能服务器 3:非阻塞型I/O及事件环形机制 4:node.js适合开发的程序 三:node.js安装 一.No ...
- --save-dev和--save的区别
使用npm来进行前端包管理的时候,我们会用到npm install或者cnpm install命令来安装需要用到的包资源 1: npm install *** --save-dev 2: npm in ...
- LINQ学习之旅(五)
Union All/Union/Intersect操作和Top/Bottom操作和Paging操作和SqlMethods操作 Union All/Union/Intersect操作 适用场景:对两个集 ...