1.  Spring 基本概念

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

在不改变原有的逻辑的基础上,增加一些额外的功能。代理也是这个功能,读写分离也能用aop来做。

2. 原理图:

我们希望业务开发人员只关心中间部分,不再需要关系开启和关闭数据库连接的情况,同时也避免了代码重复和可能出现的问题。

3. 代码

public interface UserService {
//删
void save(); String getStr(); void setStr(String str);
}
public class UserServiceImpl implements UserService {
private String str = "0"; public String getStr() {
return str;
} public void setStr(String str) {
this.str = str;
} @Override
public void save() {
System.out.println("--------- save --------------");
}
}
import org.aspectj.lang.ProceedingJoinPoint;

/**
* 自定义通知类
*/
public class MyAdvice { //before 前置通知 在目标方法前调用
public void before() {
System.out.println("before");
} //after 最终通知(后置通知)在目标方法后调用,无论是否出现异常都会执行 finally
public void after() {
System.out.println("after");
} //afterReturning 成功通知(后置通知)在目标方法执行后,并且执行成功,如果方法出现异常则不调用
public void afterReturning() {
System.out.println("afterReturning");
} //afterThrowing 异常通知(后置通知)在目标方法执行出现异常的时候才会调用
public void afterThrowing() {
System.out.println("afterThrowing");
} //around 环绕通知 需要我们手动调用目标方法,并且可以设置通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before");
Object proceed = pjp.proceed();
System.out.println("around after");
return proceed;
}
}
import com.bing.aop.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext_aop.xml")
public class AopTest { @Resource(name="userService")
UserService us;
@Test
public void Test2() {
us.save();
}
}

配置文件:文件名(applicationContext_aop.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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 目标对象 -->
<bean name="userService" class="com.bing.aop.service.UserServiceImpl"></bean> <!-- 通知对象 -->
<bean name="myAdvice" class="com.bing.aop.MyAdvice"></bean> <aop:config>
<!-- 切入点 expression 切入点表达式 可以配置要增强的方法
public void com.bing.aop.service.UserServiceImpl.save()
* com.bing.aop.service.*ServiceImpl.*(..)
id 就是唯一标识
-->
<aop:pointcut expression="execution(* com.bing.aop.service.*ServiceImpl.*(..))" id="servicePc"/> <!-- 切面 通知+切入点 -->
<aop:aspect ref="myAdvice">
<!-- 通知类型 -->
<aop:before method="before" pointcut-ref="servicePc"/>
<!-- 最终通知 后置通知 -->
<aop:after method="after" pointcut-ref="servicePc"/>
<!-- 成功通知 后置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="servicePc"/>
<!-- 异常通知 后置通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="servicePc"/>
<!-- 环绕通知-->
<aop:around method="around" pointcut-ref="servicePc"/>
</aop:aspect>
</aop:config>
</beans>

运行结果:

到这里其实发现这个AOP没有什么实际用处,前后中间执行的东西都没有关系,并不能体现真正的AOP思想。

我们将上述代码修改一下:修改环绕通知的方法。

import com.bing.aop.service.UserService;
import com.bing.aop.service.UserServiceImpl;
import org.aspectj.lang.ProceedingJoinPoint; /**
* 自定义通知类
*/
public class MyAdvice { //before 前置通知 在目标方法前调用
public void before() {
System.out.println("before");
} //after 最终通知(后置通知)在目标方法后调用,无论是否出现异常都会执行 finally
public void after() {
System.out.println("after");
} //afterReturning 成功通知(后置通知)在目标方法执行后,并且执行成功,如果方法出现异常则不调用
public void afterReturning() {
System.out.println("afterReturning");
} //afterThrowing 异常通知(后置通知)在目标方法执行出现异常的时候才会调用
public void afterThrowing() {
System.out.println("afterThrowing");
} //around 环绕通知 需要我们手动调用目标方法,并且可以设置通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
UserService userService = (UserServiceImpl)pjp.getTarget();
Object proceed = null;
if("1".equals(userService.getStr()) || "setStr".equals(pjp.getSignature().getName())){
proceed = pjp.proceed();
}
return proceed;
}
}
import com.bing.aop.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext_aop.xml")
public class AopTest { @Resource(name="userService")
UserService us;
@Test
public void Test2() {
System.out.println("设置前:------------Str == 0");
us.save();
us.setStr("1");
System.out.println("设置前:------------Str == 1");
us.save();
}
}

然后将配置文件的其他通知都去掉:

<?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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 目标对象 -->
<bean name="userService" class="com.bing.aop.service.UserServiceImpl"></bean> <!-- 通知对象 -->
<bean name="myAdvice" class="com.bing.aop.MyAdvice"></bean> <aop:config>
<!-- 切入点 expression 切入点表达式 可以配置要增强的方法
public void com.bing.aop.service.UserServiceImpl.save()
* com.bing.aop.service.*ServiceImpl.*(..)
id 就是唯一标识
-->
<aop:pointcut expression="execution(* com.bing.aop.service.*ServiceImpl.*(..))" id="servicePc"/> <!-- 切面 通知+切入点 -->
<aop:aspect ref="myAdvice">
<!-- 环绕通知-->
<aop:around method="around" pointcut-ref="servicePc"/>
</aop:aspect>
</aop:config>
</beans>

运行效果:

把实体类和MyAdvice 结合起来,可以更加方便的写你想要处理的逻辑。

XML 用的越来越少了,现在大部分都使用注解了,下面是使用注解的Demo

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; @ComponentScan("com.hundsun.cop.aop")
@Configuration
@EnableAspectJAutoProxy
public class AppConfig { }
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; @Aspect
@Component
public class MyAdvice { //设置切点
@Pointcut("execution(public * com.hundsun.cop.aop.UserService.*(..))")
public void execution(){ } // 执行前
@Before("MyAdvice.execution()")
public void before(){ } // 执行后
@After("MyAdvice.execution()")
public void after() {
System.out.println("after");
} //afterReturning 成功通知(后置通知)在目标方法执行后,并且执行成功,如果方法出现异常则不调用
@AfterReturning("MyAdvice.execution()")
public void afterReturning() {
System.out.println("afterReturning");
} //afterThrowing 异常通知(后置通知)在目标方法执行出现异常的时候才会调用
@AfterThrowing("MyAdvice.execution()")
public void afterThrowing() {
System.out.println("afterThrowing");
} //around 环绕通知 需要我们手动调用目标方法,并且可以设置通知
@Around("MyAdvice.execution()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before");
Object proceed = pjp.proceed();
System.out.println("around after");
return proceed;
}
}
public interface UserService {
void save(); String getStr(); void setStr(String str);
}
@Component
public class UserServiceImpl implements UserService {
private String str = "0"; public String getStr() {
return str;
} public void setStr(String str) {
this.str = str;
} @Override
public void save() {
System.out.println("--------- save --------------");
}
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = annotationConfigApplicationContext.getBean(UserService.class);
userService.save();
}
}

运行结果

不喜欢夸夸奇谈,实战才是真理。代码是说明原理的最可靠的方式。

总结来源:http://www.sikiedu.com/ 网站学习。

《Java Spring框架》Spring切面(AOP)配置详解的更多相关文章

  1. 【Spring】——声明式事务配置详解

    项目中用到了spring的事务: @Transactional(rollbackFor = Exception.class, transactionManager = "zebraTrans ...

  2. spring, spring mvc, mybatis整合文件配置详解

    转自:http://www.cnblogs.com/wxisme/p/4924561.html 使用SSM框架做了几个小项目了,感觉还不错是时候总结一下了.先总结一下SSM整合的文件配置.其实具体的用 ...

  3. Spring MVC的web.xml配置详解(转)

    出处http://blog.csdn.net/u010796790 1.spring 框架解决字符串编码问题:过滤器 CharacterEncodingFilter(filter-name) 2.在w ...

  4. Spring mvc的web.xml配置详解

    1.spring 框架解决字符串编码问题:过滤器 CharacterEncodingFilter(filter-name) 2.在web.xml配置监听器ContextLoaderListener(l ...

  5. Spring学习(十九)----- Spring的五种事务配置详解

    前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. ...

  6. 1、Spring MVC的web.xml配置详解(转)

    版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u010796790 1.spring 框架解决字符串编码问题:过滤器 CharacterEncodingFilt ...

  7. Spring Boot 2.0 教程 - 配置详解

    Spring Boot 可以通过properties文件,YAML文件,环境变量和命令行参数进行配置.属性值可以通过,@Value注解,Environment或者ConfigurationProper ...

  8. Spring中配置文件applicationContext.xml配置详解

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  9. spring框架的定时任务cronExpression表达式详解

    附:cronExpression表达式解释: 0 0 12 * * ?---------------在每天中午12:00触发 0 15 10 ? * *---------------每天上午10:15 ...

  10. spring boot slf4j日记记录配置详解

    https://blog.csdn.net/liuweixiao520/article/details/78900779

随机推荐

  1. 3个例子详解C++ 11 中push_back 和 emplace_back差异

    本文首发于个人博客https://kezunlin.me/post/b83bc460/,欢迎阅读最新内容! cpp11 push_back and emplace_back Guide case1 # ...

  2. J.U.C剖析与解读1(Lock的实现)

    J.U.C剖析与解读1(Lock的实现) 前言 为了节省各位的时间,我简单介绍一下这篇文章.这篇文章主要分为三块:Lock的实现,AQS的由来(通过演变的方式),JUC三大工具类的使用与原理剖析. L ...

  3. 浅谈Linux中的各种锁及其基本原理

    本文首发于:https://mp.weixin.qq.com/s/Ahb4QOnxvb2RpCJ3o7RNwg 微信公众号:后端技术指南针 0.概述 通过本文将了解到如下内容: Linux系统的并行性 ...

  4. 正则表达式 第六篇:调用CLR函数执行正则查询

    在SQL Server数据库中可以执行模糊查询,像like子句,和全文查询(Fulltext search),但是无法直接执行正则查找,SQL Server没有执行正则表达式的内置函数,但是我们可以创 ...

  5. Redis开发与运维:SDS与embstr、raw 深入理解

    对于上一篇文章,我又自己总结归纳并补充了一下,有了第二篇. 概览 <<左移 开始之前,我们先准备点东西:位运算 i<<n 总结为 i*2^n 所以 1<<5 = 2 ...

  6. ehcache监控

    引入Maven依赖 <dependency> <groupId>org.terracotta.ehcachedx.com.javabi</groupId> < ...

  7. 前后端vue和django配置

    django pip源更换 虚拟环境配置 目录和日志配置 数据库配置 用户模块自定义 异常,响应配置 xadmin vue vue基础配置 vue高级配置 vue this问题和样式配置

  8. 前端js,如何在结构化与性能中做取舍。

    js发展中的问题 随着前端web技术的发展,js要解决的问题也变得越来越多,越来越复杂. 解决更复杂的问题,需要更好的结构. 解决更复杂的问题,也需要更好的性能. 结构的优化在一定程度上会牺牲性能,同 ...

  9. 转:关于JAVA项目中CLASSPATH路径详解

    在dos下编译Java程序,就要用到classpath这个概念,尤其是在没有设置环境变量的时候.classpath就是存放.class等编译后文件的路径. javac:如果当前你要编译的Java文件中 ...

  10. python数据处理----常用数据文件的处理

    数据处理时,常用数据存储形式主要有:CSV.JSON.XML.EXCEL.数据库存储. 一.CSV文件 csv文件简介 CSV是一种通用的.相对简单的文件格式,被用户.商业和科学广泛应用.最广泛的应用 ...