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简单理解的更多相关文章

  1. Spring AOP 简单理解

    AOP技术即(面向切面编程)技术是在面向对象编程基础上的发展,AOP技术是对所有对象或一类对象编程.核心是在不增加代码的基础上,还增加了新的功能.AOP编程在开发框架本身用的比较多,而实际项目中,用的 ...

  2. Spring AOP深入理解之拦截器调用

    Spring AOP深入理解之拦截器调用 Spring AOP代理对象生成回想 上一篇博客中:深入理解Spring AOP之二代理对象生成介绍了Spring代理对象是怎样生成的,当中重点介绍了JDK动 ...

  3. Spring Aop(二)——基于Aspectj注解的Spring Aop简单实现

    转发地址:https://www.iteye.com/blog/elim-2394762 2 基于Aspectj注解的Spring Aop简单实现 Spring Aop是基于Aop框架Aspectj实 ...

  4. Spring Aop的理解和简单实现

    1.AOP概念 所说的面向切面编程其实就是在处理一系列业务逻辑的时候这一系列动作看成一个动作集合.比如连接数据库来说: 加载驱动-----获取class--------获取连接对象-------访问数 ...

  5. Spring AOP 简单入门笔记 (转)

    分享一个自己写的最为简单的Spring AOP的应用,其实,本人也是学习Spring不久,只是把一些个人的理解分享下,供参考.可能很多人刚开始不太理解到底啥是AOP,其实它也是相对 OOP来说的,类似 ...

  6. Spring aop 简单示例

    简单的记录一下spring aop的一个示例 基于两种配置方式: 基于xml配置 基于注解配置 这个例子是模拟对数据库的更改操作添加事物 其实并没有添加,只是简单的输出了一下记录 首先看下整个例子的目 ...

  7. spring aop 的理解

    spring aop的相关概念(所有的概念都是为了生成代理类这个过程所需要的信息的抽象): 1.Targer:目标对象.被代理的对象. 2.Advice:增强/通知.就是为目标对象扩展的功能.分为前置 ...

  8. Spring的AOP简单理解

    最近在研究spring的AOP,翻译出来的意思是面向切面. 总结如下: 所谓AOP就是将分散在各个方法处的公共代码提取到一处, 并通过类似拦截器的机制实现代码的动态整合.可以简单地想象成, 在某个方法 ...

  9. spring AOP简单入门

    AOP(aspect oriented programming)面向切面编程. 大致意思是在方法的执行过程中织入其他要执行的方法. 项目结构图 先介绍一下通过代理的方式实现aop,几个文件和上一篇一样 ...

随机推荐

  1. Windows Server 2008 R2 服务器系统安装图文教程

    https://www.jb51.net/os/535658.html http://www.machenike.com/article.php?id=207

  2. ubuntu 14.04 安装 OpenCV -2.4.13

    1. 安装 (1) 更新软件源 sudo apt-get update sudo apt-get upgrade (2)删除以前安装的 FFMPEG 和 x264 库: sudo apt-get re ...

  3. Sql 插入自定义主键

    在遇到数据库设计是自增的主键,且需要插入自定义的主键Id时,这个时候如果直接Insert的话,将会发生错误,错误提示信息: 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 'XXX' ...

  4. 使用zabbix3.0.4的ICMP Ping模版实现对客户端网络状态的监控

    一.登陆Zabbix服务器做以下操作: 1.fping安装 wget http://www.fping.org/dist/fping-3.16.tar.gz tar zxvf fping-3.16.t ...

  5. zabbix3.0.4使用shell脚本和zabbix自带模板两种方法添加对指定进程和端口的监控

    zabbix3.0.4添加对进程的监控: 方法一:通过自定义命令进行监控 主要思路: 通过 ps -ef|grep sdk-push-1.0.0.jar |grep -v grep|wc -l 这个命 ...

  6. bootgrid 刷新保持当前排序

    1. 前言 主要是利用了HTHNL5的localStorage技术和用ajax传输一个数组到后台并进行判断.这篇文章是解决一个小需求而来的,主要是用来记录. 2. 代码 JavaScript: var ...

  7. Mac安装Homebrew记录

    在终端输入: ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install) ...

  8. vue系列之webstrom的设置

    1.安装vue插件,方法 Setting->Plugins,点击Plugins,在右边输入vue,找到相应插件,然后安装 2.创建vue模板 注意红圈里面的 3.设置vue文件支持的样式 注意: ...

  9. MySQL 命令行工具不能向表中插入中文的解决方法

    1.报错图示 解释:sname这个字段 解析出错. 2.解决方法 打开MySQL的安装目录,找到my.ini文件,把57和81行的utf8改成gbk后 保存,最后,重启MySQL的服务 即可. 3.测 ...

  10. mysql的undo log和redo log

    在数据库系统中,既有存放数据的文件,也有存放日志的文件.日志在内存中也是有缓存Log buffer,也有磁盘文件log file,本文主要描述存放日志的文件.     MySQL中的日志文件,有这么两 ...