AOP 面向切面编程,允许在 java 应用中的方法调用的前后做一些处理。

本文通过实例介绍两种主要的Spring AOP 配置方式:xml 方式配置,注解方式配置

XML 方式配置

1. 项目包类结构

2. App.java 启动类 代码

package wqz.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class App
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[]{"SpringAOP.xml"});
CustomerService cust = (CustomerService)appContext.getBean("customerServiceProxy");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printUrl();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
}
}
}

 3. CustomerService.java 待切的类

package wqz.spring.aop;

public class CustomerService {
private String name;
private String url; public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
} public void printName(){
System.out.println("Customer name:"+this.name);
} public void printUrl(){
System.out.println("Customer url:"+this.url);
} public void printThrowException() {
throw new IllegalArgumentException();
}
}

 4. 切面处理类,有四种方式(Before,After,Around,Exception,自行百度)

package wqz.spring.aop;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice; public class HijackAfterMethod implements AfterReturningAdvice { public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("After method hijack");
}
}
package wqz.spring.aop;

import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; public class HijackAroundMethod implements MethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method name : "
+ methodInvocation.getMethod().getName());
System.out.println("Method arguments : "
+ Arrays.toString(methodInvocation.getArguments())); // 相当于 MethodBeforeAdvice
System.out.println("HijackAroundMethod : Before method hijacked!"); try {
// 调用原方法,即调用CustomerService中的方法
Object result = methodInvocation.proceed(); // 相当于 AfterReturningAdvice
System.out.println("HijackAroundMethod : After method hijacked!"); return result; } catch (IllegalArgumentException e) {
// 相当于 ThrowsAdvice
System.out.println("HijackAroundMethod : Throw exception hijacked!");
throw e;
}
}
}
package wqz.spring.aop;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice; public class HijackBeforeMethod implements MethodBeforeAdvice{ public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("HijackBeforeMethod : Before method hijacked!");
}
}
package wqz.spring.aop;

import org.springframework.aop.ThrowsAdvice;

public class HijackThrowException implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("HijackThrowException : Throw exception hijacked!");
}
}

5. Spring-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 被 监 督 对 象 创 建 -->
<bean id="customerService" class="wqz.spring.aop.CustomerService">
<property name="name" value="zoey"/>
<property name="url" value="http://shiyanlou.com"/>
</bean> <!-- Advices 4种 类 型 的 通 知 对应的类分别如下-->
<bean id="hijackBeforeMethodBean" class="wqz.spring.aop.HijackBeforeMethod"/>
<bean id="hijackAfterMethodBean" class="wqz.spring.aop.HijackAfterMethod"/>
<bean id="hijackThrowExceptionBean" class="wqz.spring.aop.HijackThrowException"/>
<bean id="hijackAroundMethodBean" class="wqz.spring.aop.HijackAroundMethod" /> <!-- PointCut 根据名字或者正则 劫持 method -->
<!-- 字符串匹配 创建 劫持bean -->
<bean id="customerPointcut"
class="org.springframework.aop.support.NameMatchMethodPointcut">
<!-- 定义劫持方法名 -->
<property name="mappedName" value="printName" />
</bean> <!-- 字符串匹配创建一个默认的Pointcut Advisor bean 用于 给 pointcut 配置 advice劫持 对象-->
<bean id="customerAdvisor"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<!-- 将 定义的 customerPointcut 劫持到的方法 交由 advice处理 -->
<property name="pointcut" ref="customerPointcut" /> <property name="advice" ref="hijackAroundMethodBean" />
</bean> <!-- 正则表达式 创建劫持bean
<bean id="customerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="hijackAroundMethodBean" />
</bean>
--> <!-- 创 建 代 理 对 象 -->
<bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 你 想 要 劫 持 的 对 象 -->
<property name="target" ref="customerService"/>
<!-- 你想使用 哪个对象 劫持 target -->
<property name="interceptorNames">
<list>
<value>customerAdvisor</value>
</list>
</property>
</bean>
</beans>

6. 运行结果

十月 24, 2018 12:30:41 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@ef98ce0: startup date [Wed Oct 24 00:30:41 CST 2018]; root of context hierarchy
十月 24, 2018 12:30:41 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [SpringAOP.xml]
十月 24, 2018 12:30:41 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6b308ce5: defining beans [customerService,hijackBeforeMethodBean,hijackAfterMethodBean,hijackThrowExceptionBean,hijackAroundMethodBean,customerPointcut,customerAdvisor,customerServiceProxy]; root of factory hierarchy
*************************
Method name : printName
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer name:zoey
HijackAroundMethod : After method hijacked!
*************************
Customer url:http://shiyanlou.com
*************************

注解方式

1. 包结构

2. 相关类代码

package wqz.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import wqz.service.UserServiceInterface; public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");
UserServiceInterface interface1 = context.getBean(UserServiceInterface.class);
interface1.sayHello();
context.close();
}
}
package wqz.service;

import org.springframework.stereotype.Service;

@Service
public class UserService implements UserServiceInterface{
public UserService() {
// TODO Auto-generated constructor stub
System.out.println(this.getClass().getSimpleName() + " constructor!!!!");
}
public void sayHello(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("========== Hello =========");
}
}
package wqz.service;

public interface UserServiceInterface {
public void sayHello();
}
package wqz.spring.aop.annotion;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Service; @Service
@Aspect
public class TimeMonitor {
@Around("execution(* wqz.service.UserService.sayHello())")
public void monitorAround(ProceedingJoinPoint pjp)throws Throwable{
System.out.println("method start time: " + System.currentTimeMillis());
Object re = pjp.proceed();
System.out.println("method end time: " + System.currentTimeMillis());
}
}

3. 运行结果

十月 24, 2018 12:56:00 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@a8e13ab: startup date [Wed Oct 24 00:56:00 CST 2018]; root of context hierarchy
十月 24, 2018 12:56:00 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [root-context.xml]
十月 24, 2018 12:56:01 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4be6d4a8: defining beans [org.springframework.aop.config.internalAutoProxyCreator,userService,timeMonitor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
UserService constructor!!!!
method start time: 1540313761817
========== Hello =========
method end time:
十月 24, 2018 12:56:02 上午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@a8e13ab: startup date [Wed Oct 24 00:56:00 CST 2018]; root of context hierarchy
十月 24, 2018 12:56:02 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory destroySingletons
信息: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4be6d4a8: defining beans [org.springframework.aop.config.internalAutoProxyCreator,userService,timeMonitor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

注解解析:

TimeMonitir 类 的注解 :

@Service和@Aspect,第一个注解是使得TimeMonitor受Spring托管并实例化。@Aspect就是使得这个类具有AOP功能(你可以这样理解)两个注解缺一不可;

@Around表示包围一个函数,也就是可以在函数执行前做一些事情,也可以在函数执行后做一些事情

"execution(* wqz.service.UserService.sayHello())"使用表达式的方式指定了要对哪个函数进行包围

补充:

@Around("within(@org.springframework.stereotype.Service wqz.spring.*)")

,意思是匹配wqz.spring包下所有使用@Service注解的类;

以下文档来自Spring中文开发指南2.5文档,由满江红开源组织翻译:

 
Spring AOP 用户可能会经常使用 execution切入点指示符。执行表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是*,它代表了匹配任意的返回类型。 一个全限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。 模式(*)匹配了一个接受一个任何类型的参数的方法。 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。更多的信息请参阅AspectJ编程指南中语言语义的部分。
下面给出一些通用切入点表达式的例子。
  • 任意公共方法的执行:
    execution(public * *(..))
  • 任何一个名字以“set”开始的方法的执行:
    execution(* set*(..))
  • AccountService接口定义的任意方法的执行:
    execution(* com.xyz.service.AccountService.*(..))
  • 在service包中定义的任意方法的执行:
    execution(* com.xyz.service.*.*(..))
  • 在service包或其子包中定义的任意方法的执行:
    execution(* com.xyz.service..*.*(..))
  • 在service包中的任意连接点(在Spring AOP中只是方法执行):
    within(com.xyz.service.*)
  • 在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):
    within(com.xyz.service..*)
  • 实现了AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
    this(com.xyz.service.AccountService)
    'this'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。
  • 实现AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):
    target(com.xyz.service.AccountService)
    'target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。
  • 任何一个只接受一个参数,并且运行时所传入的参数是Serializable 接口的连接点(在Spring AOP中只是方法执行)
    args(java.io.Serializable)
    'args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。
    请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。
  • 目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行)
    @target(org.springframework.transaction.annotation.Transactional)
    '@target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
  • 任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
    @within(org.springframework.transaction.annotation.Transactional)
    '@within'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
  • 任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行)
    @annotation(org.springframework.transaction.annotation.Transactional)
    '@annotation'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
  • 任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified 注解的连接点(在Spring AOP中只是方法执行)
    @args(com.xyz.security.Classified)
    '@args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
  • 任何一个在名为'tradeService'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
    bean(tradeService)
  • 任何一个在名字匹配通配符表达式'*Service'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
    bean(*Service)

****************************************************************

========= over ===========

Spring AOP配置方式的更多相关文章

  1. Spring AOP配置简单记录(注解及xml配置方式)

    在了解spring aop中的关键字(如:连接点(JoinPoint).切入点(PointCut).切面(Aspact).织入(Weaving).通知(Advice).目标(Target)等)后进行了 ...

  2. spring aop注解方式与xml方式配置

    注解方式 applicationContext.xml 加入下面配置 <!--Spring Aop 启用自动代理注解 --> <aop:aspectj-autoproxy proxy ...

  3. perf4j+spring+aop 配置 注解方式

    今天将perf4j基于spring aop方式进入了接入,接入方法还是比较简单.具体配置如下: logback.xml <!--perf4j配置--> <appender name= ...

  4. (转)Spring AOP实现方式(转)

    我们可以通过三种方式来使用Spring AOP,它们分别是:@Aspect-based(Annotation),Schema-based(XML),以及底层的Spring AOP API 底层的Spr ...

  5. Java--简单的Spring AOP配置以及AOP事物管理,JDK/GCLib动态代理

    一.看一下简单的通过XML的AOP配置 1.首先创建一个简单的Student类 public class Student { private Integer age; private String n ...

  6. spring aop配置文档部分翻译

    欢迎转载交流: http://www.cnblogs.com/shizhongtao/p/3476973.html 下面的文字来自官方文档的翻译,具体事例以后奉上. Advisors "ad ...

  7. spring aop配置及用例说明(1)

    欢迎转载交流,博客地址http://www.cnblogs.com/shizhongtao/p/3469776.html 首先,什么是aop,其实通俗一点讲就是,再方法执行时候我们加入其它业务逻辑.比 ...

  8. Spring AOP实现方式四之注入式AspectJ切面【附源码】

    现在我们要讲的是第四种AOP实现之注入式AspectJ切面 通过简单的配置就可以实现AOP了. 源码结构: 1.首先我们新建一个接口,love 谈恋爱接口. package com.spring.ao ...

  9. Spring AOP实现方式三之自动扫描注入【附源码】

    注解AOP实现  这里唯一不同的就是application 里面 不需要配置每个bean都需要配置了,直接自动扫描 注册,主要知识点是怎么通过配置文件得到bean, 注意类前面的@注解. 源码结构: ...

随机推荐

  1. react高阶组件

    高阶组件 为了提高组件复用性,在react中就有了HOC(Higher-Order Component)的概念.所谓的高阶组件,其本质依旧是组件,只是它返回另外一个组件,产生新的组件可以对属性进行包装 ...

  2. 如何让Excel单元格中的名字分散对齐

    1 操作方式 开始->对齐方式->对齐->水平对齐->分散对齐(缩进) 2 优势 不会破坏数据的有效性

  3. python读取指定字节长度的文本

    软件版本 Python 2.7.13;   Win 10 场景描述 1.使用python读取指定长度的文本: 2.使用python读取某一范围内的文本. Python代码 test.txt文本内包含的 ...

  4. IIC时序详解

    Verilog IIC通信实验笔记 Write by Gianttank 我实验的是 AT24C08的单字节读,单字节写,页读和页写,在高于3.3V系统中他的通信速率最高400KHZ的,我实验里用的是 ...

  5. Linux第八章:文件,文件系统的压缩,打包备份

    压缩:gzip  -v  文件名 1:压缩后成  文件名.gz 的压缩文件,原文件消失 2:压缩的文件可以直接使用zcat  文件名.gz 读取里面的内容 解压缩: gunzip   文件名.gz 替 ...

  6. Node学习笔记(二)

    1.package.json详解Node.js 在调用某个包时,会首先检查包中 package.json 文件的 main 字段,将其作为包的接口模块,如果 package.json 或 main 字 ...

  7. mysql 使用 GROUP BY 时报错 ERROR 1055 (42000)

    解决方法1:SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));这种修改只是暂时性的,还是在 my.ini 文件中的sq ...

  8. Eclipse Debug不能热部署解决

    摘要: Eclipse Debug不能热部署代码may be out-of-synch 问题描述:Project通过ant工具编译部署到JBoss下,在使用Eclipse远程调试功...       ...

  9. Android 开发 框架系列 Google的ORM框架 Room

    目录 简介 导入工程 使用流程概况 一个简单的小Demo 深入学习 @Entity使用 自定义表名 tableName  自定义字段名@ColumnInfo 主键 @PrimaryKey 索引 @In ...

  10. 1816647 - Error "Data file of SAP Note is incomplete" uploading a note in SNOTE

    ymptom When uploading an SAP Note in transaction SNOTE you receive the error "Data file of SAP ...