Java的Spring框架中AOP项目的一般配置和部署教程

0.关于AOP
面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP是OOP的延续。

主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。

主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

在Spring中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

1.通过PropertyPlaceholderConfigurer在Spring中加载其他外部配置文件或者属性文件:
在很多javaEE工程中,Spring的角色非常重要,是一个管理其他模块和组件的轻量级容器,Spring经常需要管理Struts、Ibatis、Hibernate等,这些开源框架的配置文件就通过Spring的PropertyPlaceholderConfigurer加载在Spring中进行管理,另外,数据库连接信息、JNDI连接信息属性文件等也可以通过PropertyPlaceholderConfigurer加载到Spring中来管理。用法如下:
(1).通过PropertyPlaceholderConfigurer将其他文件加载到Spring中:
在spring配置文件中添加如下配置:

<bean class=“org.springframework.beans.factory.config.PropertyPlaceholderConfigurer“>
    <property name=“locations“>
       <value>classpath:要加载的文件名</value>
       ……
    </property>
</bean>

(2).经过(1)中的配置要加载的配置或属性文件就被加载到spring中,如果还需要在运行时使用加载进来的配置或数据文件的一些信息,如使用数据库连接信息或者JNDI连接信息时,就可以使用类型EL表达式的语法进行引用,例如:

<bean id=”dataSource” destroy-method=”close” class=”org.apache.common.dbcp.BasicDataSource”>
    <!--假设数据库连接信息写在外部属性文件中,已经被spring加载-->
    <property name=”driverClassName” value=”${driver}”/>
    <property name=”url” value=”${url}”/>
    <property name=”username” value=”${username}”/>
    <property name=”password” value=”${password}”/>
</bean>

注意:也可以使用<context:Property-Placeholderlocation=”classpath:要加载的文件名”/>

2.Java的动态代理:
Spring的面向切面编程(AOP)底层实现原理是动态代理,因此在学习面向切面编程之前必须先了解动态代理。
Java中动态代理应用非常广泛,动态代理是23中设计模式中非常常用的经典设计模式之一。动态代理的原理是,当要调用一个目标对象或者其方法时,系统并不是直接返回目标对象,而是返回一个代理对象,通过这个代理对象去访问目标对象或者目标对象的方法。
动态代理的简单原理如下:
客户端调用者——>代理对象——>被调用的目标对象。
当客户端调用代理对象时,代理对象委派目标对象调用其业务方法。
动态代理分为两种,针对接口的动态代理和针对普通类的动态代理,java中的动态代理是真的接口的动态代理,cglib是针对普通类的动态代理,目标javaEE的依赖包和Spring的jar包中已经包含了cglib相关jar包,因此即可以对代理也可以对普通类进行动态代理。
(1).java的针对接口动态代理:
Java中的动态代理只能针对接口进行动态代理,因此,目标对象必须实现接口,代理对象要实现目标对象的所有接口。工作流程如下:

a.动态代理类编写:
注意:动态代理必须实现InvocationHandler接口,同时实现以下方法:
 

复制代码 代码如下:

Object invoke(Objectm代理实例,Method代理实例上调用的接口方法的Method 实例,Object[] 传入代理实例上方法调用的参数值的对象数组);

安装JDK的文档说明,该方法作用是传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。

b.创建代理对象:

Proxy.newProxyInstance(类加载器, Class<?>[]接口数组,回调代理对象(一般是this))

当调用目标对象方法时,通过该方法创建目标对象的代理对象,代理对象会自动调用其invoke方法调用目标对象,并将调用结果返回。

(2).cglib针对普通java类动态代理:
cglib创建动态代理时,不要求目标类必须实现接口,其工作流程如下:
a.动态代理类编写:

Enhancer enhancer = new Enhancer();
//设置目标类的父类为其本身
enhancer.setSuperclass(目标类对象.getClass());
//设置回调对象为动态代理对象本身
enhancer.setCallback(this);

b.实现MethodInterceptor接口:
实现以下方法:

Object intercept(Objectm代理实例,Method代理实例上调用的接口方法的Method 实例,Object[] 传入代理实例上方法调用的参数值的对象数组,MethodProxy 方法代理实例); 
 
注意:cglib不但可以针对类动态代理,还可以针对方法动态代理。

3.面向切面编程(AOP)的基础概念:
以一个普通的java方法来举例

public 返回类型 方法名(参数列表){ ——>环绕通知
    方法前处理代码  ——>   前置通知
try{
    方法具体实现(方法体)…….
    方法后处理代码  ——>   后置通知
}Catch(异常类型 e){
    异常处理……    ——>   例外通知
}finally{
    最后处理代理……    ——>   最终通知
}
}

a. 横切关注点:如上面5个通知的位置,在java对象中,可以这些具有类似共同处理逻辑的位置加入如权限验证、事物处理、日志记录等处理逻辑的对象称为横切关注点,面向对象编程(OOP)的关注点是纵向将现实世界的事物抽象成编程的对象模型。而面向切面编程(AOP)的关注点是横向的,它将编程对象模型中拥有类似处理逻辑的地方抽象出来形成切面,而编程对象中的处理逻辑就是横切关注点。
b. 切面(Aspect):将横切关注点抽象就形成切面,与类类似,二者关注点不同,类是事物特性的抽象,切面是横切关注点的抽象。
c. 连接点(Joinpoint):被拦截到的点,在Spring中指方法,因为spring只支持方法类型的连接点,即被拦截的方法。如上面例子的方法。
d. 切入点(Pointcut):指对连接点进行拦截的定义,是连接点的集合,即一系列被拦截方法的集合。
e. 通知(Advice):指拦截到连接点之后要做的事情,即拦截之后的逻辑处理。通常的权限验证、事物处理、日志记录等操作就是在通知中定义和完成的。
f. 目标对象(Target):代理的目标对象,即被拦截的对象。如上面例子中方法所在的对象。
g. 织入(Weave):指将切面应用到目标对象,并导致代理对象创建的过程。
h. 引入(Introduction):在不修改代码的前提下,引入可以在运行期为类动态的添加一些方法和字段。

4. Spring中支持面向切面编程(AOP)的依赖包:
Spring解压后目录中的如下3个包:

lib/aspectj/aspectjweaver.jar
lib/aspectj/aspectjrt.jar
lib/cglib/cglib-nodep-2.1-3.jar

5. 在spring中使用面向切面编程(AOP)时,需要在spring配置文件中引入aop的命名空间,即添加如下的配置:

xmlns:aop=”http://www.springframework.org/schema/aop”
“http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”

注意:Spring2.5以后提供两种AOP方法,即基于xml配置文件方式和基于java注解方式。
若要使用注解方式的aop,需要在spring配置文件中添加如下的对象注解方式aop的支持:

<aop:aspectj-autoProxy/>

6. JavaBean的包装类——BeanWrapper:
Spring通过BeanWrapper类封装一个javabean的行为,可以设置和获取其属性值,如:

BeanWrapper 包装类对象 = BeanWrapperImpl(new 被包装类());
包装类对象.setPropertyValue(“属性名”,”属性值”);

通过这种方法就可以给被包装类设置属性。

7. 基于注解方式的面向切面编程(AOP)开发:
(1).在spring配置文件中加入对注解方法的aop支持。
(2).定义切面:
和创建普通类类似,在类前加上”@Aspect”注解,表明该类是一个切面。
(3).在切面中加入切入点:
切入点就是被拦截对象方法的集合,通常切入点定义在切面中某个对切入点进行处理的方法上。使用”@Pointcut”注解,语法如下:

@Pointcut(“execution(* com.test.service..*.*(..))”)
public void anyMethod(){//方法名为切入点名
切入点处理
}

语法参数详解:
a. 第一个”*”:表示被拦截的方法是任意的返回类型。
b. com.test.service:这里是举一个简单的例子,表示要被拦截的包名,即被拦截的包。
c.被拦截包名后面的两个”..”:表示被拦截包下面的子包也递归进行拦截,即被拦截的子包。
d. ”..”之后的”*”:表示被拦截包及其子包下面的所有类,即被拦截的类。
e. 最后一个”*”:表示被拦截类中的所有方法,即被拦截的方法。
f. ”(..)”:表示被拦截的方法接收任意的参数,即被拦截的参数。
注意:切入点定义语法可以支持通配符,但是一定要严格遵循语法规则。如:

@Pointcut(“execution(*com.test.service..*.add*(..))”)

表示对com.test.service包及其子包下所有的类中以”add”开头的方法进行拦截。
(4).在切面中添加通知:
Spring中通知位置请参看3中的小例子。
”@Before”注解:声明前置通知。
“@AfterRutruning”注解:声明后置通知。
“@After”注解:声明最终通知。
“@AfterThrowing”注解:声明例外通知。
“@Around”注解:声明环绕通知。
一个定义通知的例子如下:

@Before(“anyMethod()(切面中声明的切入点名)”)
public void doAccessCheck(){
    ……
}

注意:环绕通知和其他4种通知的稍有不同,环绕通知的定义方式比较特别,环绕通知在整个方法调用前后都会起作用,因此必须使用连接点对象告诉连接点在环绕通知处理之后继续其逻辑处理。其定义方式如下:

@Around(切入点名)
public Object doBasicProfiling(ProcedingJoinPoint pjp) throws Throwable{
    ……
    return pjp.proceed();//该句是告诉连接点继续执行其他的操作
}

8.基于注解方式的面向切面编程(AOP)开发的一些小技巧:
(1).获取输入参数:
如:

@Before(“切入点名 && args(输入参数名)”)
public void doSomething(String 输入参数名){……}

(2).获取返回结果:
如:

@AfterReturning(Pointcut=”切入点名”,returning=”返回结果名”)
public void dosomething(String 结果名){……}

9.基于XML方式的面向切面编程(AOP)开发:
(1).定义切面类,在切面类中添加通知。
(2).将切面类想普通java类一样在spring配置文件中配置。
(3).在spring配置文件中添加AOP配置如下:

<aop:config>
    <!--配置切面-->
    <aop:aspect id=”切面id” ref=”spring配置文件中切面类的id”>
       <!--配置切入点-->
       <aop:pointcut id=”切入点id”
expression=”execution(* com.test.service..*.*(..))”/>
       <!--配置通知-->
       <aop:before pointcut-ref=”切入点id” method=”切面类中相应的处理方法”/>
       <aop:after ……/>
       ……
</aop:aspect>
</aop:config>

10. Spring的事务处理(Spring的声明式事务处理):
事务简单来说是指数据库中的一条最基本的操作,关于事务的详细讲解以后会在数据库相关总结中具体说明。Spring的面向切面编程(AOP)一个最重要的应用是事务管理,Spring2.5以后版本的事务管理支持基于注解的方式和基于XML文件的方式两种:
(1).基于注解方式的事务管理:
a. 在spring配置文件中添加事务管理的命名空间如下:

xmlns:ts=http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

b. 在spring配置文件中配置事务管理器如下:

<bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
    <property name=”dataSource” ref=”spring中配置的数据源bean的id”/>
</bean>

c.在spring配置文件中添加支持注解方式的事务配置项如下:

<tx:annotation-driventransaction-managertx:annotation-driventransaction-manager=”txManager(spring中配置的事务管理器bean的id)”/>

d.使用基于注解的事务管理:
在Spring所管理的JavaEE工程中,需要使用事务的业务逻辑地方加上“@Transactional”注解。

(2).基于XML文件方式的事务管理:
a. 在spring配置文件中配置事务管理器如下:

<bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
    <property name=”dataSource” ref=”spring中配置的数据源bean的id”/>
</bean>

b.在spring配置文件中添加事物管理的切面如下:

<aop:config>
    <!--配置事务切入点-->
    <aop:pointcut id=”transactionPointcut”
Expression=”execution(* com.test.service..*.*(..))”/>
<!--配置事务通知-->
<aop:advisor advice-ref=”txAdvice” pointcut-ref=”transactionPointcut”/>
</aop:config>

c.在spring配置文件中为事务通知添加事物处理特性如下:


<tx:advice id=”txAdvice” transactionManager=”txManager”>
    <tx:attributes>
       <!--这里举例将以get开头的查询方法设置为只读,不支持事务-->
       <tx:method name=”get*” read-only=”true” propagation=”NOT_SUPPORTED”/>
       <!--其他的方法设置为spring默认的事物行为-->
       <tx:method name=”*”/>
    </tx:attributes>
</tx:advice> 

时间: 2016-04-26

深入浅析Spring 的aop实现原理

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

spring基础概念AOP与动态代理理解

一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 以简单模拟事务的执行过程说明各种代理区别 1.1 静态代理 由程序员创建或由特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. public interface PersonDao { vo

spring-boot使用AOP统一处理日志

AOP我想大家都很清楚,有时候我们需要处理一些请求日志,或者对某些方法进行一些监控,如果出现例外情况应该进行怎么样的处理,现在,我们从spring-boot中引入AOP. [开发环境:jdk版本号为1.8,spring boot的版本号为1.4.1]{style="background-color:#FF0000"} 首先,我们先引入jar包, POM文件添加如下内容: <!--引用AOP--> <dependency> <groupId>org.s

spring aop两种配置方式

第一种:注解配置AOP 注解配置AOP(使用 AspectJ 类库实现的),大致分为三步: 1. 使用注解@Aspect来定义一个切面,在切面中定义切入点(@Pointcut),通知类型(@Before, @AfterReturning,@After,@AfterThrowing,@Around). 2. 开发需要被拦截的类. 3. 将切面配置到xml中,当然,我们也可以使用自动扫描Bean的方式.这样的话,那就交由Spring AoP容器管理. 另外需要引用 aspectJ 的 jar 包:

Spring使用AspectJ注解和XML配置实现AOP

本文演示的是Spring中使用AspectJ注解和XML配置两种方式实现AOP 下面是使用AspectJ注解实现AOP的Java Project 首先是位于classpath下的applicationContext.xml文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmln

实例讲解Java的Spring框架中的AOP实现

简介 面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足. 除了类(classes)以外,AOP提供了 切面.切面对关注点进行模块化,例如横切多个类型和对象的事务管理. (这些关注点术语通常称作 横切(crosscutting) 关注点.) Spring的一个关键的组件就是 AOP框架. 尽管如此,Spring IoC容器并不依赖于AOP,这意味着你可以自由选择是否使用AOP,AOP提供强大的中间件解决方案,这使得Spring IoC容器更加完善

Spring AOP切面解决数据库读写分离实例详解

Spring AOP切面解决数据库读写分离实例详解 为了减轻数据库的压力,一般会使用数据库主从(master/slave)的方式,但是这种方式会给应用程序带来一定的麻烦,比如说,应用程序如何做到把数据写到master库,而读取数据的时候,从slave库读取.如果应用程序判断失误,把数据写入到slave库,会给系统造成致命的打击. 解决读写分离的方案很多,常用的有SQL解析.动态设置数据源.SQL解析主要是通过分析sql语句是insert/select/update/delete中的哪一种,从而对

利用Spring AOP记录方法的执行时间

一.前言 对于spring aop这个我就不多介绍了,网上一搜一大把,使用过spring的人都知道spring的ioc和aop.ioc我们常用,但在我们自己的系统中,aop的使用几乎为零,除了这个监控的小功能应用到了,其他的基本上没有使用到.下面小编就给大家整理下利用Spring AOP记录方法执行时间的解决方案,有需要的一起看看吧. 二.解决方案 1.传统方法 最简单.粗暴的方法是给各个需要统计的方法开始和结尾处加的时间戳,然后差值计算结果即可,代码如下: long startTime = S

利用spring AOP记录用户操作日志的方法示例

前言 最近项目已经开发完成,但发现需要加用户操作日志,如果返回去加也不太现实,所以使用springAOP来完成比较合适.下面来一起看看详细的介绍: 注解工具类: @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface LogAnnotation { String operateModelNm() default ""; String operateFuncNm() default

spring boot aop 记录方法执行时间代码示例

本文研究的主要是spring boot aop 记录方法执行时间的实现代码,具体如下. 为了性能调优,需要先统计出来每个方法的执行时间,直接在方法前后log输出太麻烦,可以用AOP来加入时间统计 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency&

利用spring aop实现动态代理

下面由我来给大家展示用spring aop实现动态代理的例子(电脑打印) 下面就看一下具体的代码: 先定义一个打印机的接口 package aop007_ComPrint; public interface Print { public void ColorPrint(); //彩色打印 public void WhitePrint(); //黑白打印 } 然后定义两个实现类,分别实现彩色打印和黑白打印 package aop007_ComPrint; public class ColorPri

SpringBoot项目中使用AOP的方法

本文介绍了SpringBoot项目中使用AOP的方法,分享给大家,具体如下: 1.概述 将通用的逻辑用AOP技术实现可以极大的简化程序的编写,例如验签.鉴权等.Spring的声明式事务也是通过AOP技术实现的. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-aop Spring的AOP技术主要有4个核心概念: Pointcut: 切点,用于定义哪个方法会被拦截,例如 execution(* cn.sp

Spring Aop之AspectJ注解配置实现日志管理的方法

最近项目要做一个日志功能,我用Spring Aop的注解方式来实现. 创建日志注解 package com.wyj.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lan

Spring AOP面向切面编程实现原理方法详解

1. 什么是AOP AOP (Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现在不修改源代码的情况下,给程序动态统一添加功能的一种技术,可以理解成动态代理.是Spring框架中的一个重要内容.利用 AOP 可以对业务逻辑的各个部分进行隔离,使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发的效率 2. Spring AOP ①. AOP 在Spring中的作用 提供声明式事务:允许用户自定义切面 ②. AOP 的基本概

利用注解配置Spring容器的方法

本文介绍了利用注解配置Spring容器的方法,分享给大家,具体如下: @Configuration标注在类上,相当于将该类作为spring的xml的标签 @Configuration public class SpringConfiguration { public SpringConfiguration() { System.out.println("初始化Spring容器"); } } 主函数进行测试 public class Main { public static void m

spring aop的简单使用方法详解

AOP:[动态代理] 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式: 1.导入aop模块:Spring AOP:(spring-aspects) 2.定义一个业务逻辑类(MathCalculator):在业务逻辑运行的时候将日志进行打印(方法之前.方法运行结束.方法出现异常,xxx) 3.定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行: 通知方法: 前置通知(@Before):logSta

spring AOP的After增强实现方法实例分析

本文实例讲述了spring AOP的After增强实现方法.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmln