Spring框架的AOP
Spring学习笔记(四)
本文目录
1 AOP的介绍
2 Spring的AspectJ实现AOP(annotation)
3 Spring的AspectJ实现AOP (XML)
Spring文档http://docs.spring.io/spring/docs/4.0.0.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/
一 AOP介绍
spect Oriented Programming(AOP),面向切面编程。AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间降低耦合的隔离效果
简单来说就是在方法的前后加一层过滤的方法
如果类实现了interface接口,通过使用动态代理(Proxy),通过拦截一个对象的行为并添加我们需要的功能来完成
如果没有实现接口的类,可以使用Cglib代理实现AOP
AOP用途比较广,适合切面的功能都可以使用AOP,比如打日志,声明式的事务的管理,性能测试,权限检查等
通过invocationhandle和Proxy实现
测试代码
接口DO
package proxy.service; public interface Do {
public void doSomething(); }
DO接口的实现
package proxy.service; public class DoImpl implements Do { @Override
public void doSomething() {
System.out.println("doimpl..."); } }
动态代理的实现,invocationhandle和Proxy
package proxy.service; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class dynamicProxy implements InvocationHandler {
private Object target; public dynamicProxy(Object target) {
this.target = target;
} public void before(Method method) {
System.out.println(method.getName() + "调用开始");
} public void after(Method method) {
System.out.println(method.getName() + "调用结束");
} public static Object newInstance(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new dynamicProxy(target));
} @Override
public Object invoke(Object proxy, Method method, Object[] args) {
Object result = null;
try {
before(method);
result = method.invoke(target, args);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
after(method);
}
return result;
}
}
测试类
package proxy.service.test; import static org.junit.Assert.*; import org.junit.Before;
import org.junit.Test; import proxy.service.Do;
import proxy.service.DoImpl;
import proxy.service.dynamicProxy; public class dynamicProxyTest { @Before
public void setUp() throws Exception {
} @Test
public void testDynamicProxy() {
Do doSth = (Do) dynamicProxy.newInstance(new DoImpl());
doSth.doSomething();
}
}
执行结果
doSomething调用开始
doimpl...
doSomething调用结束
在不改动实现类和接口的情况下,通过invocationhandle和Proxy实现动态代理在方法的前后插入了业务逻辑
二、Spring的AspectJ实现AOP(annotation)
1 添加JAR包
aspectjrt.jar aspectjweaver.jar
2 XML的配置
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:annotation-config/>
<context:component-scan base-package="com"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
3 新建切面类
package com.aop; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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 logInterceptor {
@Before("execution(public void com.daoImpl.UserDaoImpl.*(..))")
public void beforMethod(){
System.out.println("aspectJ before method");
}
@AfterReturning("execution(public void com.daoImpl.UserDaoImpl.*(..))")
public void afterMethod(){
System.out.println("aspectJ after method");
} }
@Aspect在类名上方注解表示实现Aspect的类
@Before表示方法运行前
@AfterReturning表示在方法执行之后
他们的语法建议记住 execution即可
execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?) 除了返回类型模式、方法名模式和参数模式外,其它项都是可选的,可使用通配符
例如
execution( public void com.daoImpl.UserDaoImpl.* (com.entity.User) )//这里没有异常
(<修饰符模式>? <返回类型模式> <方法名模式> (<参数模式>) <异常模式>?)
具体详见传送门http://dylanxu.iteye.com/blog/1312454
测试类
package com.serviceImpl.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.entity.User;
import com.serviceImpl.UserServiceImpl; public class UserServiceImplTest {
User user; @Before
public void setUp() throws Exception {
user = new User();
user.setName("testName");
user.setRemark("testRemark");
} @Test
public void testAdd() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl");
UserServiceImpl.add(user);//调用方法
UserServiceImpl.update(user);//调用方法
}
}
执行结果
aspectJ before method
testName-->testRemark save --调用UserDaoImpl!
aspectJ after method
aspectJ before method
testName-->testRemark update --调用UserDaoImpl!
aspectJ after method
通过@Aspect,@Before,@AfterReturning 成功的在方法的前后加入了切面逻辑
介绍另外几个常用的annotation
@Pointcut
@Pointcut("execution(public void com.daoImpl.UserDaoImpl.*(com.entity.User))")
Pointcut提供了一个切面的切入点切必须写在一个空方法上面
public class logInterceptor {
@Pointcut("execution(public void com.daoImpl.UserDaoImpl.*(com.entity.User))")
public void myAop(){}; @Before("myAop()")
public void beforMethod(){
System.out.println("aspectJ before method");
}
@AfterReturning("myAop()")
public void afterMethod(){
System.out.println("aspectJ after method");
}
}
@Before("myAop()") 效果等于 @Before("execution(public void com.daoImpl.UserDaoImpl.*(com.entity.User))")
执行效果与之前的执行效果一致
@Around
@Around("execution(public void com.daoImpl.UserDaoImpl.*(com.entity.User))")
Around标签,可循环执行方法 注意---> pjp.proceed();重复了三次
package com.aop; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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 logInterceptor {
@Pointcut("execution(public void com.daoImpl.UserDaoImpl.*(com.entity.User))")
public void myAop(){};
@Around("myAop()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("aspectJ before method");
pjp.proceed();
pjp.proceed();
pjp.proceed();
System.out.println("aspectJ after method");
}
}
测试类
package com.serviceImpl.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.entity.User;
import com.serviceImpl.UserServiceImpl; public class UserServiceImplTest {
User user; @Before
public void setUp() throws Exception {
user = new User();
user.setName("testName");
user.setRemark("testRemark");
} @Test
public void testAdd() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl");
UserServiceImpl.add(user);//调用方法
UserServiceImpl.update(user);//调用方法
}
}
执行结果
aspectJ before method
testName-->testRemark save --调用UserDaoImpl!
testName-->testRemark save --调用UserDaoImpl!
testName-->testRemark save --调用UserDaoImpl!
aspectJ after method
aspectJ before method
testName-->testRemark update --调用UserDaoImpl!
testName-->testRemark update --调用UserDaoImpl!
testName-->testRemark update --调用UserDaoImpl!
aspectJ after method
pjp.proceed();重复了三次
从结果中得到方法也确实执行了三次
通过around可以有效控制方法在这个切面里的执行次数,甚至不执行
annotation介绍到这里
通过上述资料可以掌握 @Aspect @Pointcut @Before @AfterReturning @Around 以及 execution语法
3 Spring的AspectJ实现AOP (XML)
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:annotation-config/>
<context:component-scan base-package="com"></context:component-scan>
<aop:config>
<aop:aspect id="logInterceptor" ref="logInterceptor">
<aop:pointcut expression="execution(public void com.daoImpl.UserDaoImpl.*(..))" id="myAop" />
<aop:before pointcut-ref="myAop" method="beforMethod" /><aop:after pointcut-ref="myAop" method="afterMethod" />
</aop:aspect>
</aop:config> </beans>
由于我使用的是annotation的component组件bean配置
定义<aop:config>配置
aspect的ref表示Spring管理的bean,id应该是随意的
pointcut +表达式 + id(方法名)
before/after在与method方法之间需要+表达式或者是pointcut的id来明确切入点
切面类
package com.aop; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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; @Component
public class logInterceptor {
public void myAop(){};
public void beforMethod(){
System.out.println("aspectJ before method");
}
public void afterMethod(){
System.out.println("aspectJ after method");
}
// @Around("myAop()")
// public void around(ProceedingJoinPoint pjp) throws Throwable{
// System.out.println("aspectJ before method");
// pjp.proceed();
// System.out.println(pjp.getStaticPart());
// System.out.println("aspectJ after method");
// } }
测试类
package com.serviceImpl.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.entity.User;
import com.serviceImpl.UserServiceImpl; public class UserServiceImplTest {
User user; @Before
public void setUp() throws Exception {
user = new User();
user.setName("testName");
user.setRemark("testRemark");
} @Test
public void testAdd() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl");
UserServiceImpl.add(user);//调用方法
UserServiceImpl.update(user);//调用方法
}
}
执行结果与annotation的一致
aspectJ before method
testName-->testRemark save --调用UserDaoImpl!
aspectJ after method
aspectJ before method
testName-->testRemark update --调用UserDaoImpl!
aspectJ after method
around的XML配置
<aop:aspect id="logInterceptor" ref="logInterceptor">
<aop:pointcut expression="execution(public void com.daoImpl.UserDaoImpl.*(..))" id="myAop" />
<aop:before pointcut-ref="myAop" method="beforMethod" /><aop:after pointcut-ref="myAop" method="afterMethod" />
<aop:around pointcut-ref="myAop" method="around"/>
</aop:aspect>
切面类
package com.aop; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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; @Component
public class logInterceptor {
public void myAop(){};
public void beforMethod(){
System.out.println("aspectJ before method");
}
public void afterMethod(){
System.out.println("aspectJ after method");
}
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("aspectJ before method");
pjp.proceed();
System.out.println(pjp.getStaticPart());
System.out.println("aspectJ after method");
} }
执行结果
aspectJ before method
aspectJ before method
testName-->testRemark save --调用UserDaoImpl!
aspectJ after method
execution(void com.dao.UserDao.save(User))
aspectJ after method
aspectJ before method
aspectJ before method
testName-->testRemark update --调用UserDaoImpl!
aspectJ after method
execution(void com.dao.UserDao.update(User))
aspectJ after method
个人建议使用XML来完成AOP的切面配置,这样代码的可读性会比较强,而且配置较为灵活。
另外如果非实现接口的类需要做切面处理的话,需要引入JAR包,这里没继续研究。
通过上述资料可以掌握 @Aspect @Pointcut @Before @AfterReturning @Around注解和XML配置 以及 execution语法
Spring框架的AOP的更多相关文章
- Spring框架的AOP技术(注解方式)
1. 步骤一:创建JavaWEB项目,引入具体的开发的jar包 * 先引入Spring框架开发的基本开发包 * 再引入Spring框架的AOP的开发包 * spring的传统AOP的开发的包 * sp ...
- 10.Spring——框架的AOP
1.Spring 框架的 AOP 2.Spring 中基于 AOP 的 XML架构 3.Spring 中基于 AOP 的 @AspectJ 1.Spring 框架的 AOP Spring 框架的一个关 ...
- Spring 框架的 AOP 简介
Spring 框架的 AOP Spring 框架的一个关键组件是面向方面的编程(AOP)(也称为面向切面编程)框架. 面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点. 跨一个应用程序的多 ...
- 使用spring框架进行aop编程实现方法调用前日志输出
aop编程 之使用spring框架实现方法调用前日志输出 使用spring框架实现AOP编程首先需要搭建spring框架环境: 使用Spring框架实现AOP工程编程之后,不需要我们去写代理工厂了,工 ...
- Spring框架之AOP源码完全解析
Spring框架之AOP源码完全解析 Spring可以说是Java企业开发里最重要的技术.Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Orie ...
- Spring框架(4)---AOP讲解铺垫
AOP讲解铺垫 不得不说,刚开始去理解这个Aop是有点难理解的,主要还是新的概念比较多,对于初学者一下子不一定马上能够快速吸收,所以我先对什么事Aop做一个解释: 首先说明:本文不是自己所写 ...
- Spring框架的AOP的底层实现
1. Srping框架的AOP技术底层也是采用的代理技术,代理的方式提供了两种 1. 基于JDK的动态代理 * 必须是面向接口的,只有实现了具体接口的类才能生成代理对象 2. 基于CGLIB动态代理 ...
- Spring 框架的AOP之注解的方式
1. 环境搭建 1.1 导入 jar 包 Spring 框架的基本开发包(6个); Spring 的传统AOP的开发包 spring-aop-4.3.10.RELEASE org.aopallianc ...
- Spring框架及AOP
Spring核心概念 Spring框架大约由20个功能模块组成,这些模块主分为六个部分: Core Container :基础部分,提供了IoC特性. Data Access/Integration ...
- spring框架中AOP思想与各种配置详解
Spring中提供两种AOP支持: 1.基于代理的经典AOP 2.Aspectj注解配置AOP 首先我们先了解什么是AOP,AOP(Aspect Oriented Programming ...
随机推荐
- 完全卸载TeamViewer与重新安装TeamViewer 7(含单文件版V12主控端)
卸载teamviewer: 删除:%AppData%\Teamviewer.%tmp%\TeamViewer.C:\Users\Administrator\AppData\Local\TeamView ...
- HDU5200 数据离线处理
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5200 ,数据离线处理. 这是BestCoder Round #36的C题,比赛时自己用线段树做,姿势不 ...
- 博弈论经典算法(一)——对抗搜索与Alpha-Beta剪枝
前言 在一些复杂的博弈论题目中,每一轮操作都可能有许多决策,于是就会形成一棵庞大的博弈树. 而有一些博弈论题没有什么规律,针对这样的问题,我们就需要用一些十分玄学的算法. 例如对抗搜索. 对抗搜索简介 ...
- mac 远程桌面提示: 证书或相关链无效
左上角 RDC -->首选项-->安全性-->即使验证失败,也始终链接
- DongDong坐飞机
题目连接:https://ac.nowcoder.com/acm/contest/904/D 第一次研究了一下这种题型,还是比较好理解的,因为有半价次数的限制,所以要把每一中情况都写出来,dp[现在的 ...
- 解决Win10桌面右键卡顿一直转圈圈的
把系统重置之后,发现在桌面点击右键时一直转圈,但是在文件夹等非桌面位置都正常.可能是我之前修改注册表添加右键选项造成的,也可能不是,因为将修改的地方删除还是没有解决问题,555. 上网搜素一波,发现大 ...
- 如何着手学习一个新的PHP框架
如今的PHP框架层出不穷,名气也各不相同.如何快速掌握一种框架?看看本文吧~ 如今的PHP框架层出不穷,名气也各不相同.我不是这方面的专家,甚至不能熟练地使用其中的一种,所以就不作推荐了.这里我要讨论 ...
- JS - OOP-继承的最佳实现方式
如上图,使用第三种方式实现继承最好,也就是加了下划线的. 但是Object.create方法是ES6才支持的,所以,右边就写了一个实现其同样功能的函数.
- HTTP 配置与编译安装
目录 HTTP 配置与编译安装 HTTP 相关配置 DSO 定义'Main' Server 的文档页面路径 定义站点主页面 站点访问控制常见机制 基于源地址实现访问控制 日志设定 设定默认字符集 定义 ...
- 二十五、MySQL 索引
MySQL 索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索 ...