AOP,Aspect Oriented Programming,意为面向切面编程,是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。一般应用于事物管理,性能监视,安全检查,缓存,日志等。

  • AOP实现原理

AOP底层是采用代理的机制进行实现。如果是一个实现类(接口的实现类),Spring会采用jdk的动态代理Proxy。如果只是一个类,Spring会采用cglib字节码增强。

关于动态代理可以参考我的另一篇博文:https://www.cnblogs.com/chichung/p/10358444.html

1.动态代理的方式

目标类:

切面类:

工厂类:

2.cglib增强字节码的方式

先导入jar包:

核心:hibernate-distribution-3.6.10.Final\lib\bytecode\cglib\cglib-2.2.jar

依赖:struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib\asm-3.3.jar

注意:spring-core.jar已经整合以上两个内容了,现在只不过是我们自己实现原理才使用的。

目标类和切面类写法一样,工厂类:


  • Spring编写半自动代理

导包:Spring核心4+1依赖包,AOP联盟(规范,是一个依赖包,com.springsource.org.aopalliance)+Spring-aop(实现,aop包)

(1)目标类

public interface UserService {
public abstract void addNewUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao; @Override
public void addNewUser() {
// 业务逻辑操作
System.out.println("addNewUser的操作");
}
}

(2)切面类

public class MyAspect implements MethodInterceptor {

    @Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("执行方法前的代码");
Object obj = mi.proceed();
System.out.println("执行方法后的代码");
return obj;
}
}

(3)Spring配置

<?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: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"> <!--业务类-->
<bean id="userService" class="com.chichung.service.impl.UserServiceImpl"></bean>
<!--切面类-->
<bean id="myAspect" class="com.chichung.aspect.MyAspect"></bean>
<!--使用工厂bean创建代理-->
<bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.chichung.service.UserService"></property>
<property name="target" ref="userService"></property>
<property name="interceptorNames" value="myAspect"></property>
</bean>
</beans>

默认采用的是jdk动态代理原理,如果使用cglib的原理创建代理,加上:

<property name="optimize" value="true"></property>

(4)测试类

public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("proxyService");
userService.addNewUser();
}
}

  • Spring AOP全自动编程

导包:Spring核心4+1依赖包,AOP联盟(规范,是一个依赖包,com.springsource.org.aopalliance)+Spring-aop(实现,aop包)+

spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE(依赖包)

(1)目标类:

public interface UserService {
public abstract void addNewUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao; @Override
public void addNewUser() {
// 业务逻辑操作
System.out.println("addNewUser的操作");
}
}

(2)切面类:

public class MyAspect implements MethodInterceptor {

    @Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("执行方法前的代码");
Object obj = mi.proceed();
System.out.println("执行方法后的代码");
return obj;
}
}

(3)Spring配置

(4)测试类:

public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.addNewUser();
}
}

  • 重点:通过AspectJ实现Spring AOP

AspectJ是一个基于Java语言的AOP框架。Spring2.0以后新增了对AspectJ切点表达式支持。新版本的Spring框架,建议使用AspectJ方式来开发AOP。

导包

aopalliance AOP联盟规范,spring-aop的依赖包
spring-aop AOP实现
aspectj.weaver AspectJ规范,spring-aspects的依赖包
spring-aspects AspectJ实现

1.AspectJ的通知类型

before:前置通知(应用:各种校验)

在方法执行前执行,如果通知抛出异常,阻止方法运行

afterReturning:后置通知(应用:常规数据处理)

方法正常返回后执行,如果方法中抛出异常,通知无法执行

必须在方法执行后才执行,所以可以获得方法的返回值。

around:环绕通知(应用:十分多,例如事务)

方法执行前后分别执行,可以阻止方法的执行

必须手动执行目标方法

afterThrowing:抛出异常通知(应用:包装异常信息)

方法抛出异常后执行,如果方法没有抛出异常,无法执行

after:最终通知(应用:清理现场)

方法执行完毕后执行,无论方法中是否出现异常

2.切入点表达式

execution()  用于描述方法

语法:execution(修饰符  返回值  包.类.方法名(参数) throws异常)

修饰符,一般省略。

public 公共方法

* 任意

返回值,不能省略。

void 返回没有值

String 返回值字符串。

* 任意

com.gyf.crm 固定包

com.gyf.crm.*.service crm包下面子包任意 (例如:com.gyf.crm.staff.service)

com.gyf.crm.. crm包下面的所有子包(含自己)

UserServiceImpl 指定类

*Impl 以Impl结尾

User* 以User开头

* 任意

方法名,不能省略

addUser 固定方法

add* 以add开头

*Do 以Do结尾

* 任意

(参数)

() 无参

(int) 一个整型

(int ,int) 两个

(..) 参数任意

throws ,可省略,一般不写

下面的是很少用或者基本不用的:

within:

匹配包或子包中的方法

this:

匹配实现接口的代理对象中的方法

target:

匹配实现接口的目标对象中的方法

args:

匹配参数格式符合标准的方法

bean(id)  

对指定的bean所有的方法

3.AspectJ案例(基于xml配置)

(1)before前置通知、afterReturning后置通知、afterThrowing抛出异常通知、after最终通知的XML配置。

目标类:

public interface UserService {
public abstract void addNewUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao; @Override
public void addNewUser() {
// 业务逻辑操作
System.out.println("addNewUser的操作");
}
}

切面类(不用再实现MethodInterceptor接口)

public class MyAspect{
public void myBefore(){
System.out.println("执行方法前的代码");
} public void myAfter(){
System.out.println("执行方法后的代码");
}
}

Spring配置

<?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:context = "http://www.springframework.org/schema/context"
xmlns:aop = "http://www.springframework.org/schema/aop"
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">

  <!--业务类-->
  <bean id="userService" class="com.chichung.service.impl.UserServiceImpl"></bean>
<!--切面类-->
  <bean id="myAspect" class="com.chichung.aspect.MyAspect"></bean>
<!--proxy-target-class="true"表示用cglib字节码增强方式来实现-->
<!--proxy-target-class="false"表示用动态代理的方式来实现-->
<aop:config proxy-target-class="true">
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointCut" expression="execution(* com.chichung.service.impl.*.*(..))"></aop:pointcut>
<aop:before method="myBefore" pointcut-ref="myPointCut"></aop:before>
<aop:after method="myAfter" pointcut-ref="myPointCut"></aop:after>
</aop:aspect>
</aop:config>
</beans>

测试类:

public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.addNewUser();
}
}

(2)around环绕通知的XML配置(与前置通知后置通知稍微有点不同)

目标类跟上面都是一样。

切面类:

public class MyAspect{
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("执行方法前的代码");
Object obj = pjp.proceed();
System.out.println("执行方法后的代码");
return obj;
} }

Spring配置:

<?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:context = "http://www.springframework.org/schema/context"
xmlns:aop = "http://www.springframework.org/schema/aop"
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"> <!--业务类-->
<bean id="userService" class="com.chichung.service.impl.UserServiceImpl"></bean>
<!--切面类-->
<bean id="myAspect" class="com.chichung.aspect.MyAspect"></bean> <!--proxy-target-class="true"表示用cglib字节码增强方式来实现-->
<!--proxy-target-class="false"表示用动态代理的方式来实现-->
<aop:config proxy-target-class="true">
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointCut" expression="execution(* com.chichung.service.impl.*.*(..))"></aop:pointcut>
<aop:around method="myAround" pointcut-ref="myPointCut"></aop:around>
</aop:aspect>
</aop:config>
</beans>

测试类和上面的示例一样。

(3)总结:

3.AspectJ案例(基于注解配置)

(1)声明使用注解

<?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:context = "http://www.springframework.org/schema/context"
xmlns:aop = "http://www.springframework.org/schema/aop"
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:annotation-config>
<!--扫描注解-->
<context:component-scan base-package="com.chichung"></context:component-scan>
<!--确定AOP注解生效-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

(2)替换service和切面bean

@Component("userService")
public class UserServiceImpl implements UserService {
private UserDao userDao; @Override
public void addNewUser() {
// 业务逻辑操作
System.out.println("addNewUser的操作");
}
}
@Component("myAspect")
public class MyAspect{
...

(3)声明切面

@Component("myAspect")
@Aspect
public class MyAspect{
...
<!--声明切面-->
<aop:config>
<aop:aspect ref="myAspect"></aop:aspect>
</aop:config>

(4)声明公共切入点

@Component("myAspect")
@Aspect
public class MyAspect{
@Pointcut("execution(* com.chichung.service.impl.*.*(..))")
public void myPointCut(){};
...

(5)声明环绕通知(其他通知也类似,不一一举例了)

@Component("myAspect")
@Aspect
public class MyAspect{
@Pointcut("execution(* com.chichung.service.impl.*.*(..))")
public void myPointCut(){}; @Around("myPointCut()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("执行方法前的代码");
Object obj = pjp.proceed();
System.out.println("执行方法后的代码");
return obj;
} }

(6)测试类与之前的一样。

Spring框架的基本使用(AOP部分)的更多相关文章

  1. Spring框架IOC容器和AOP解析 非常 有用

    Spring框架IOC容器和AOP解析   主要分析点: 一.Spring开源框架的简介  二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面 ...

  2. Spring框架IOC容器和AOP解析

    主要分析点: 一.Spring开源框架的简介  二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面向切面编程(AOP)和事务管理配置  一.S ...

  3. Spring框架(6)---AspectJ实现AOP

    AspectJ实现AOP 上一篇文章Spring框架(4)---AOP讲解铺垫,讲了一些基础AOP理解性的东西,那么这篇文章真正开始讲解AOP 通过AspectJ实现AOP要比普通的实现Aop要方便的 ...

  4. Spring框架(四)AOP面向切面编程

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  5. Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术

    第3章--AOP技术 Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.o ...

  6. 深入学习Spring框架(三)- AOP面向切面

    1.什么是AOP? AOP为 Aspect Oriented Programming 的缩写,即面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术..AOP是OOP的延续, ...

  7. Spring框架之IoC和AOP

    Spring框架简介: 2003年2月,Spring框架正式成为一个开源项目,并发布于SourceForge中.致力于Java EE应用的各种解决方案,而并不是仅仅专注于某一层的方案,是企业应用开发的 ...

  8. Spring 框架基础(04):AOP切面编程概念,几种实现方式演示

    本文源码:GitHub·点这里 || GitEE·点这里 一.AOP基础简介 1.切面编程简介 AOP全称:Aspect Oriented Programming,面向切面编程.通过预编译方式和运行期 ...

  9. spring框架DI(IOC)和AOP 原理及方案

    http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html http://www.oschina.net/code/snippe ...

随机推荐

  1. java-----遇到问题------myeclipse----发布项目到tomcat中lib文件夹没有子项目产生ClassNotFoundException错误

    情况 myeclipse发布项目到tomcat中lib文件夹没有子项目产生ClassNotFoundException错误. 这种情况一般是 .classpath文件设置的输出路径不对导致的. 1.. ...

  2. Java Learning之文档注释

    文档注释的结构 文档注释主体的开头是一句话,概述类型或成员的作用,应自成一体.后面可跟其他句子或段落,用以详细说明类.接口.方法或字段. 除了这些描述性的段落以外,后也可跟其他段落,数量不限,并且每段 ...

  3. bzoj 1503

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 12311  Solved: 4399[Submit][Stat ...

  4. Docker图形界面管理之Portainer

    介绍 Portainer是一个开源.轻量级Docker管理用户界面,基于Docker API,可管理Docker主机或Swarm集群,支持最新版Docker和Swarm模式.官方文档 https:// ...

  5. day19 IO编程

    文件:文件是数据源(保存数据的地方)的一种. 文件在程序中是以流的形式来操作的 内存(程序)到文件是输出流,文件到内存(程序)是输入流. 字节流:可用于读写的二进制文件及任何类型文件. 字符流:可以用 ...

  6. wav文件格式及ffmpeg处理命令

    wav文件头详解 符合RIFF(Resource Interchange File Format)规范的wav文件的文件头记录了音频流的编码参数等基本信息.wav文件由多个块组成,至少包含RIFF标志 ...

  7. 快速搭建Spring Boot项目

    Spring boot是Spring推出的一个轻量化web框架,主要解决了Spring对于小型项目饱受诟病的配置和开发速度问题. Spring Boot 包含的特性如下: 创建可以独立运行的 Spri ...

  8. 2017 清北济南考前刷题Day 2 afternoon

    期望得分:100+60+70=230 实际得分:0+60+0=60 T1 可以证明如果一对括号原本就匹配,那么这对括号在最优解中一定不会被分开 所以用栈记录下没有匹配的括号 最后栈中一定是 一堆右括号 ...

  9. Redis学习四:解析配置文件 redis.conf

    一.它在哪 地址: 思考:为什么要将它拷贝出来单独执行? 二.Units单位 1 配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit 2 对大小写不敏感 三.INCLUDES包 ...

  10. 使用lombok提高编码效率

    通过gettter,setter注解lombok已经帮我们自动生成了getter,setter方法!