使用Spring AOP实现业务依赖解耦

Spring IOC用于解决对象依赖之间的解耦,而Spring AOP则用于解决业务依赖之间的解耦;

统一在一个地方定义【通用功能】,通过声明的方式定义这些通用的功能以何种【方式】【织入】到某些【特定应用】里去,并且【不需要修改】特定应用的代码;
-1通用功能:<aop:aspect>如日志、安全或事务,具体的方法动作称为Advice;
-2方式:<aop:before|after-returning|around>如方法调用、字段修改和抛出异常,Spring AOP仅支持方法调用(method execution join point);
-3织入:Weaving时期:编译期,类加载期和运行期,Spring AOP仅支持运行期植入;
-4 特定应用:<aop:pointcut>,匹配连接点,也就是指定aspect适配的目标方法;
-5不需要修改:动态为目标类创建代理对象,不需要修改业务代码本身;

AspectJ的功能比Spring AOP更加全面,如果需要可以在Spring中加载AspectJ的功能模块;使用Spring AOP除了常规Spring的jar包外还需要引入aspectjweaver-[xxx].jar;

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans">
 3   <!-- Config for IOC -->
 4   <context:component-scan base-package="com.active.leo.helloworld" />
 5   <context:property-placeholder location="classpath:service.properties" />
 6   <import resource="webmvc-config.xml" />
 7
 8   <!-- Config for AOP -->
 9   <aop:aspectj-autoproxy />
10   <bean id="audience" class="com.active.leo.helloworld.Audience" />
11
12   <aop:config>
13     <aop:aspect ref="audience">
14       <aop:pointcut id="performance"
15            expression="execution(* com.active.leo.helloorld.Performer.perform(..))" />
16
17       <aop:before pointcut-ref="performance" method="takeSeats" />
18       <aop:before pointcut-ref="performance" method="turnOffCellPhones" />
19       <aop:after-returning pointcut-ref="performance" method="applaud" />
20       <aop:after-throwing  pointcut-ref="performance" method="demandRefund" />
21     </aop:aspect>
22   </aop:config>
23 </bean>
24 </beans>

-1 <aop:aspct>表示定义一个切面,并且与名为audience的切面实现类关联;
-2 <aop:pointcut>表示定义一个名为performance的切点,并与需要进行AOP的目标业务方法绑定;execution的目标方法匹配的pattern:

1 execution([modifiers?] [return-type] [declaring –type?] [func-name]([param-name]) [throw-exp?] )

其他的还有within(表示被某个注解标注的所有类), this, target和args;

-3 <aop:before>表示调用目标业务perform方法之前触发AOP,perform方法一定会执行;
-4 <aop:after-returning>表示调用perform方法触发正常结束之后触发AOP;
-5 <aop:after-throwing>表示调用perform方法抛出异常后触发AOP;
-6 <aop:around>合并before和after-returning,PreceedingJoinPoint.proceed()为目标动作;可以控制执行流程,可根据情况决定是否执行perform方法;
如果目标动作有参数,可以借助arg/arg-names在切面方法中获取;

通过注解实现Spring AOP
首先要创建一个用于config的Java Bean,
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}
然后通过@Aspect,@Pointcut,@Before,@AfterReturning,@Around等实现;所有使用AspectJ标注的前提条件是JavaBean可以被ClassLoader发现,所以需要额外添加@Component用于被IOC容器发现;被申明为Aspect的JavaBean不能用于其他Aspect的auto-proxying;

一般的Aspect的生命周期都是singleton,当然也可以设置成perflow, perthis, pertypewithin, pertarget的不同周期;实现org.springFramework.core.Ordered接口,重写getOrder()方法可以控制当前advice在目标方法周边的执行有限顺序;

 1 public class App {
 2     public void func1() {}
 3     public void func2() {}
 4 }
 5
 6 @Aspect
 7 public class SpringAopAspectDemo implements Ordered {
 8
 9     @Pointcut("execution(* com.test.spring.aspectj.App.func1(..))")
10     public void pointcut4Func1() {}
11
12     @Pointcut("execution(* com.test.spring.aspectj.App.func2(..))")
13     public void pointcut4Func2() {}
14
15     @Around("pointcut4Func1()")
16     public Object doDevice(ProceedingJoinPoint pjp) throws Throwable {
17         //something needs to be done in aspect.
18     }
19 }

使用@Interface实现自定义注解
通过@Interface自定义注解,并结合spring AOP可以实现针对request的权限校验,

 1 @Target(ElementType.METHOD)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 public @interface PermissionRequired {
 4   boolean isReqiureAuth default false;
 5   boolean isRequireAuzh default false;
 6 }
 7
 8 >>>>>>>>>>>>>
 9
10 @Pointcut("execution(* com.ychen.application.*.*(..)) && "
11             + "@annotation(requiredPermission)")
12     public void pointController(RequiredPermission requiredPermission) {
13         // nothing
14 }
15
16 @Around("pointController(requiredPermission)")
17 public Object applySecurityCheck(ProceedingJoinPoint point,
18     RequiredPermission requiredPermission) throws Throwable {
19   // auth check
20 }

Spring AOP使用JDK Dynamic Proxy和CGLIB对目标类进行代理:
#1 JDK Dynamic Proxy方式使用Java Reflection技术,实现InvocationHandler接口,因此要求目标类有一个Interface,并且目标方法需要在此Interface中申明,动态创建一个实现了Interface的类并在该类中调用目标类的方法;

 1 public class PerformanceMonitorProxy implements InvocationHandler {
 2
 3   private Object target;
 4   public ServiceWithPerformanceMonitorProxy(Object target) {
 5     this.target = target;
 6   }
 7   public static Object newProxyInstance(Object target) {
 8     Class clazz = target.getClass();
 9     return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
10               new ServiceWithPerformanceMonitorProxy(target));
11   }
12   @Override
13   public Object invoke(Object proxy, Method method, Object[] args)
14         throws Throwable {
15     //do something before target function invocation
16     PerformanceMonitor.begin(method.getName());
17     Object result = method.invoke(target, args);
18     //do something after target function invocation
19     PerformanceMonitor.end(method.getName());
20     return result;
21   }
22 }

#2 CGLIB使用字节码技术,实现MethodInterceptor接口,动态生成一个目标类的子类,通过over-write去覆盖目标方法的执行,并在子类方法中调用目标方法的前后进行AOP;

 1 public class CGlibProxy implements MethodInterceptor {
 2   private Enhancer enhancer = new Enhancer();
 3   public Object getProxy(Class clazz) {
 4     enhancer.setSuperclass(clazz);
 5     // 代理执行时会回调此this持有的intercept方法,以实现代码织入
 6     enhancer.setCallback(this);
 7     return enhancer.create();
 8   }
 9
10   @Override
11   public Object intercept(Object target, Method method, Object[] args,
12       MethodProxy methodProxy) throws Throwable {
13     PerformanceMonitor.begin(method.getName());
14     Object result = methodProxy.invokeSuper(target, args);
15     // 下面这样是无法执行原有方法的,因为这里的target并不是原有类的实例,而是代理类的实例
16     // target :
17     // com.dianping.aop.AdminServiceImpl$$EnhancerByCGLIB$$225da297@16dd5a9d
18     // Object result = method.invoke(target, args);
19     PerformanceMonitor.end(method.getName());
20     return result;
21   }
22 }

Spring一般首选JDK Dynamic Proxy进行代理,如果遇到没有实现Interface的情况则使用CGLIB,当然可以通过下属设置强制使用CGLIB;

1 <aop:config proxy-target-class="true">
2     <!-- other beans defined here... -->
3 </aop:config>

原文地址:https://www.cnblogs.com/leo-chen-2014/p/10567243.html

时间: 2024-09-29 10:28:22

使用Spring AOP实现业务依赖解耦的相关文章

Spring AOP 实现业务日志记录

1. 用户管理业务逻辑接口(UserManagerApplogic.java ) Java代码   package com.iteye.applogic; public interface UserManagerApplogic { public void addUser(String name); } 2. 用户管理业务逻辑实现类(UserManagerApplogicImpl.java) Java代码   package com.iteye.applogic.impl; import org

spring aop 拦截业务方法,实现权限控制

难点:aop类是普通的java类,session是无法注入的,那么在有状态的系统中如何获取用户相关信息呢,session是必经之路啊,获取session就变的很重要.思索很久没有办法,后来在网上看到了解决办法. 思路是:      i. SysContext  成员变量 request,session,response     ii. Filter 目的是给 SysContext 中的成员赋值     iii.然后在AOP中使用这个SysContext的值   要用好,需要理解  ThreadL

Spring AOP基于注解的“零配置”方式实现

为了在Spring中启动@AspectJ支持,需要在类加载路径下新增两个AspectJ库:aspectjweaver.jar和aspectjrt.jar.除此之外,Spring AOP还需要依赖一个aopalliance.jar包 定义一个类似ServiceAspect.java这样的切面bean: 1 package com.hyq.aop; 2 3 import org.apache.commons.logging.Log; 4 import org.apache.commons.loggi

spring Aop 注解

个人理解: spring Aop 是什么:面向切面编程,类似于自定义拦截操作,支持拦截之前操作@Before,拦截之后操作@After,拦截环绕操作@Around. 什么情况下使用spring Aop:举例如下 当需要统计某些方法 or 指定xx开头的方法名 or 指定xx结尾的方法名 or 某些类下的方法 or 某些包下的方法 or 所有的方法的耗时统计或添加日志信息时,使用spring Aop 切面编程可以不用修改任何需要统计或添加日志的方法,只需很少一部分代码实现需要做的操作. 某交易系统

Spring AOP 学习例子

http://outofmemory.cn/code-snippet/3762/Spring-AOP-learn-example 工作忙,时间紧,不过事情再多,学习是必须的.记得以前的部门老大说过:“开发人员不可能一天到晚只有工作,肯定是需要自我学习.第一:为了更充实自己,保持进步状态.第二:为了提升技术,提高开发能力.第三:保持程序员对技术和学习的热情,工作的激情.程序员还是需要把基础打扎实,修炼自己的内功.” 所以赶紧把学习的东西总结一下,加深印象.之前有说了下AOP的原理 (http://

Spring AOP常见面试题

一.AOP是什么? 与OOP对比,面向切面,传统的OOP开发中的代码逻辑是至上而下的过程中会长生一些横切性问题,这些横切性的问题和我们的主业务逻辑关系不会散落在代码的各个地方,造成难以维护,AOP的编程思想就是把业务逻辑和横切的问题进行分离,从而达到解耦的目的,使代码的重用性和开发效率高(目的是重用代码,把公共的代码抽取出来) 二.AOP的应用场景 1.日志记录 2.权限验证 3.效率检查 4.事务管理 三.springAop的底层技术 1.JDK动态代理 2.CGLIB代理 问题:是编译时期进

JavaEE学习之Spring aop

一.基本概念 AOP——Aspect-Oriented Programming,面向切面编程,它是spring框架的一个重要组成部分.一般的业务逻辑都有先后关系,我们可以理解为纵向关系,而AOP关注的是横向关系,每一个关注点可以理解为一个横切面.例如我们的大部分代码都会涉及到日志记录,很多的数据库操作都会涉及到事务的创建和提交.那么从横向关注这些逻辑,他们都一个个的切面. AOP技术的具体实现,可以通过动态代理技术或者是在程序编译期间进行静态的"织入"方式.AOP经常使用的场景包括:日

深入理解Spring AOP之基本概念

深入理解Spring AOP之基本概念 AOP到底是什么 Spring AOP和IOC是听到的关于Spring最频繁的两个词了.现在来重点关注AOP这个词,IOC先放一边,下面这段话摘自Spring优势中关于面向切面的介绍: 面向切面--Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发.应用对象只实现它们应该做的--完成业务逻辑--仅此而已.它们并不负责(甚至是意识)其它的系统级关

Spring AOP 实现原理(二) 使用 Spring AOP

与 AspectJ 相同的是,Spring AOP 同样需要对目标类进行增强,也就是生成新的 AOP 代理类:与 AspectJ 不同的是,Spring AOP 无需使用任何特殊 命令对 Java 源代码进行编译,它采用运行时动态地.在内存中临时生成"代理类"的方式来生成 AOP 代理. Spring 允许使用 AspectJ Annotation 用于定义方面(Aspect).切入点(Pointcut)和增强处理(Advice),Spring 框架则可识别并根据这些 Annotati