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. Linux磁盘分区、挂载

    ⒈Linux下磁盘说明 1)Linux硬盘分IDE硬盘和SCSI硬盘,目前基本上是SCSI硬盘. 2)对于IDE硬盘,使用“hdx~”标识符,“hd”代表IDE硬盘.   对于SCSI硬盘,使用“sd ...

  2. Bootstrap2.x与Bootstrap3.x的区别

    做项目时,有时也会参考别的案例的优秀之处.在用Bootstrap的时候,发现很多项目代码都有区别,在<div>布局class上,有用.span*,有用.col-md-*,实际上是Boots ...

  3. List Control控件

    List Control控件 显示方式 属性[View]选择成[Report]. 添加成员变量 绑定变量:m_listCtrl 设置值 // 表头添加 m_listCtrl.SetExtendedSt ...

  4. 【Mysql sql inject】【入门篇】SQLi-Labs使用 part 2【12-14】

    这几关主要是考察POST形式的SQLi注入闭合 ## Less-12 - POST - Error Based- Double quotes- String ### 1)知识点 主要考察报错注入中的双 ...

  5. 【转】Python数据类型之“集合(Sets)与映射(Mapping)”

    [转]Python数据类型之“集合(Sets)与映射(Mapping)” 一.集合类型(Sets) 集合对象是不同的(不可重复)hashable对象的无序集合.常见用法包括:成员关系测试.移除序列中的 ...

  6. C# 清理消息管道的消息

    using System;using System.Collections.Generic;using System.Linq;using System.Messaging;using System. ...

  7. 【转】SourceInsight4破解笔记

    时隔好多年,sourceinsight4以迅雷不及掩耳之势的来了.与3.5相比,sourceinsight4多了代码折叠以及文件标签功能,可谓是让sourceinsight迷兴奋了好几晚上.废话不多说 ...

  8. Log4j maven依赖配置

    做项目的时候,经常需要给应用打印日志,LOG4J是我们的不二选择,项目管理使用maven构建时,pom.xml配置如下 <!--日志 start--> <dependency> ...

  9. Java用四种方法实现阶乘n! (factorial)

    1. 引言 实现阶乘的方法很多,这边介绍四种方法,分别是递归,尾递归,循环和BigDecimal. 2. 代码 public class Test { public static void main( ...

  10. dubbo作为消费者注册过程分析--????

    请支持原创: http://www.cnblogs.com/donlianli/p/3847676.html   作者当前分析的版本为2.5.x.作者在分析的时候,都是带着疑问去查看代码,debug进 ...