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. go中的关键字-go(下)

    1. goroutine源码分析 1.1 初始化 go程序的启动流程分为四步 call osinit, 这里就是设置了全局变量ncpu = cpu核心数量 call schedinit make &a ...

  2. linux history(命令历史)

    1.bash中默认命令记忆可达1000个.这些命令保存在主文件夹内的.bash_history中. 2.~/.bash_history:记录的是前一次登录以前所执行过的命令.至于本次登录的命令暂时存储 ...

  3. Java常见网络操作(URL类,InetAddress类,URLConnection类)

    *****************InetAddress********************** InetAddress:用于标识网络上的硬件资源(如,IP,主机名,域名等).    对于Inet ...

  4. yum运行报错:libcurl.so.4: cannot open shared object file: No such file or directory

    /usr/lib64/目录下存在libcurl.so.4文件 CURL的动态库找不到,这里我们加入到ld.so.conf [root@localhost bin]#  vim /etc/ld.so.c ...

  5. yum运行报错:File "/usr/libexec/urlgrabber-ext-down", line 28

    [root@sdw1 bin]# vim /usr/libexec/urlgrabber-ext-down 再次执行yum命令,正常下载

  6. day20191010ClassNotes

    笔记: 1.DAO模式组成部分: 程序 ----> 数据库 实体类 数据库中的表 工具类:公共的数据库连接.关闭.公共的增删改.查询 接口 : 程序提倡的是面向接口编程,从而降低程序的耦合性 实 ...

  7. 小程序如何判断用户(后台使用Django)

    小程序如何判断用户是哪个: 有Web开发经验的都知道,客户端用户发起请求,服务器收到请求后,可以通过把用户user_id记录到session里,然后下次通过session里面的user_id来辨别是哪 ...

  8. MySQL 高可用架构 之 MHA (Centos 7.5 MySQL 5.7.18 MHA 0.58)

    目录 简介 环境准备 秘钥互信 安装基础依赖包 安装MHA组件 安装 MHA Node组件 安装 MHA Manager 组件 建立 MySQL 一主三从 初始化 MySQL 启动MySQL 并简单配 ...

  9. c语言l博客作业03

    问题 答案 这个作业属于哪个课程 c语言程序设计ll 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-3/homework/8727 我在这 ...

  10. 怎么把宿主机上的镜像推送到hub上

    怎么把宿主机上的镜像推送到hub上: 1.查看系统中存在的镜像: [root@izuf63bjp8ts8nkl13pxh1z devicemapper]# docker imagesREPOSITOR ...