AOP,aspect object programming 面向切面编程
功能: 让关注点代码与业务代码分离!
关注点
重复代码就叫做关注点
切面
关注点形成的类,就叫切面(类)!
面向切面编程,就是指对很多功能都有的重复的代码抽取,再在运行的时候往业务方法上动态植入“切面类代码”。
切入点
执行目标对象方法,动态植入切面代码。
可以通过切入点表达式,指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码。
Spring AOP的4个jar包
a) spring-aop-3.2.5.RELEASE.jar 【位于spring-framework-3.2.5.RELEASE/libs目录内】
b) aopalliance-.jar
aopalliance-.jar http://www.java2s.com/Code/Jar/a/Downloadaopalliancejar.htm
aopalliance-1.0-sources.jar http://www.java2s.com/Code/Jar/a/Downloadaopalliance10sourcesjar.htm
c) aspectjrt.jar 和 aspectjweaver.jar(aspectj是优秀的aop组件)
AspectJ 1.8.7 http://www.eclipse.org/aspectj/downloads.php
aspectj-1.8.7.jar http://www.eclipse.org/downloads/download.php?file=/tools/aspectj/aspectj-1.8.7.jar
aspectj-1.8.7-src.jar http://www.eclipse.org/downloads/download.php?file=/tools/aspectj/aspectj-1.8.7-src.jar
aspectj-1.8.7.jar和aspectj-1.8.7-src.jar实际是压缩包,可以将后缀名改为".rar",再打开之后,可以看到里面的jar包。
步骤:
1) 先引入aop相关的4个jar文件
2) bean.xml中引入aop名称空间 xmlns:aop
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 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" default-autowire="byType"> </beans>
3) 开启aop注解
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4) 使用注解
@Aspect 指定一个类为切面类
@Pointcut("execution(* cn.rk.spring.aop_annotation.*.*(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
applicationContext.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:p="http://www.springframework.org/schema/p" 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" default-autowire="byType"> <!-- 开启注解扫描 --> <context:component-scan base-package="com.rk.hibernate.f_aop_annotation"></context:component-scan> <!-- 开启aop注解方式 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
IUserDao.java
package com.rk.hibernate.f_aop_annotation; //接口 public interface IUserDao { void save(); }
UserDao.java
package com.rk.hibernate.f_aop_annotation; import org.springframework.stereotype.Component; /** * 目标对象 */ @Component // 加入IOC容器 public class UserDao implements IUserDao { @Override public void save() { System.out.println("-----核心业务:保存!!!------"); // int a = 1/0; } }
OrderDao.java
package com.rk.hibernate.f_aop_annotation; import org.springframework.stereotype.Component; /** * 目标对象 * */ @Component public class OrderDao { public void save() { System.out.println("-----核心业务:保存!!!------"); } }
Aop.java
package com.rk.hibernate.f_aop_annotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; 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 @Aspect // 指定当前类为切面类 public class Aop { // 指定切入点表达式: 拦截哪些方法; 即为哪些类生成代理对象 @Pointcut("execution(* com.rk.hibernate.f_aop_annotation.*.*(..))") public void point_cut() { } // 前置通知 : 在执行目标方法之前执行 @Before("point_cut()") public void before() { System.out.println("Aop.before()"); } // 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】 @After("point_cut()") public void after() { System.out.println("Aop.after()"); } // 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】 @AfterReturning("point_cut()") public void afterReturning() { System.out.println("Aop.afterReturning()"); } // 异常通知: 当目标方法执行异常时候执行此关注点代码 @AfterThrowing("point_cut()") public void afterThrowing() { System.out.println("Aop.afterThrowing()"); } // 环绕通知:环绕目标方式执行 @Around("point_cut()") public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前...."); pjp.proceed(); // 执行目标方法 System.out.println("环绕后...."); } }
App.java
package com.rk.hibernate.f_aop_annotation; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { private ApplicationContext ac = new ClassPathXmlApplicationContext("/com/rk/hibernate/f_aop_annotation/applicationContext.xml"); @Test public void test() { // 目标对象有实现接口,spring会自动选择“JDK代理” IUserDao userDao = (IUserDao) ac.getBean("userDao"); System.out.println(userDao.getClass()); userDao.save(); System.out.println(); System.out.println("----------------------------------------"); System.out.println(); // 目标对象没有实现接口, spring会用“cglib代理” OrderDao orderDao = (OrderDao) ac.getBean("orderDao"); System.out.println(orderDao.getClass()); orderDao.save(); } }
输出:
class com.sun.proxy.$Proxy12 环绕前.... Aop.before() -----核心业务:保存!!!------ 环绕后.... Aop.after() Aop.afterReturning() ---------------------------------------- class com.rk.hibernate.f_aop_annotation.OrderDao$$EnhancerByCGLIB$$9b746598 环绕前.... Aop.before() -----核心业务:保存!!!------ 环绕后.... Aop.after() Aop.afterReturning()
使用XML方式实现aop编程的步骤:
1) 引入jar文件 【aop 相关jar, 4个】
2) 引入aop名称空间 xmls:aop
3)aop 配置
--> 配置切面类 (重复执行代码形成的类)
--> aop配置:拦截哪些方法 / 拦截到方法后应用通知代码
applicationContext.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:p="http://www.springframework.org/schema/p" 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" default-autowire="byType"> <!-- dao 实例 --> <bean id="userDao" class="com.rk.hibernate.g_aop_xml.UserDao"></bean> <bean id="orderDao" class="com.rk.hibernate.g_aop_xml.OrderDao"></bean> <!-- 切面类 --> <bean id="aop" class="com.rk.hibernate.g_aop_xml.Aop"></bean> <!-- Aop配置 --> <aop:config> <!-- 定义一个切入点表达式: 拦截哪些方法 --> <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.g_aop_xml.UserDao.*(..))"/> <!-- 切面 --> <aop:aspect ref="aop"> <!-- 环绕通知 --> <aop:around method="around" pointcut-ref="pt"/> <!-- 前置通知: 在目标方法调用前执行 --> <aop:before method="before" pointcut-ref="pt"/> <!-- 后置通知: --> <aop:after method="after" pointcut-ref="pt"/> <!-- 返回后通知 --> <aop:after-returning method="afterReturning" pointcut-ref="pt"/> <!-- 异常通知 --> <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/> </aop:aspect> </aop:config> </beans>
IUserDao.java
package com.rk.hibernate.g_aop_xml; //接口 public interface IUserDao { void save(); }
UserDao.java
package com.rk.hibernate.g_aop_xml; /** * 目标对象 */ public class UserDao implements IUserDao { @Override public void save() { System.out.println("-----核心业务:保存!!!------"); // int a = 1/0; } }
OrderDao.java
package com.rk.hibernate.g_aop_xml; /** * 目标对象 * */ public class OrderDao { public void save() { System.out.println("-----核心业务:保存!!!------"); } }
Aop.java
package com.rk.hibernate.g_aop_xml; import org.aspectj.lang.ProceedingJoinPoint; public class Aop { public void point_cut() { } public void before() { System.out.println("Aop.before()"); } public void after() { System.out.println("Aop.after()"); } public void afterReturning() { System.out.println("Aop.afterReturning()"); } public void afterThrowing() { System.out.println("Aop.afterThrowing()"); } public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前...."); pjp.proceed(); // 执行目标方法 System.out.println("环绕后...."); } }
App.java
package com.rk.hibernate.g_aop_xml; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { private ApplicationContext ac = new ClassPathXmlApplicationContext("/com/rk/hibernate/g_aop_xml/applicationContext.xml"); @Test public void test() { // 目标对象有实现接口,spring会自动选择“JDK代理” IUserDao userDao = (IUserDao) ac.getBean("userDao"); System.out.println(userDao.getClass()); userDao.save(); System.out.println(); System.out.println("----------------------------------------"); System.out.println(); // 目标对象没有实现接口, spring会用“cglib代理” OrderDao orderDao = (OrderDao) ac.getBean("orderDao"); System.out.println(orderDao.getClass()); orderDao.save(); } }
输出:
class com.sun.proxy.$Proxy4 环绕前.... Aop.before() -----核心业务:保存!!!------ 环绕后.... Aop.after() Aop.afterReturning() ---------------------------------------- class com.rk.hibernate.g_aop_xml.OrderDao -----核心业务:保存!!!------
切入点表达式:可以对指定的“方法”进行拦截; 从而给指定的方法所在的类生层代理对象。
applicationContext.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:p="http://www.springframework.org/schema/p" 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" default-autowire="byType"> <!-- dao 实例 --> <bean id="userDao" class="com.rk.hibernate.h_aop_pointcut.UserDao"></bean> <bean id="orderDao" class="com.rk.hibernate.h_aop_pointcut.OrderDao"></bean> <!-- 切面类 --> <bean id="aop" class="com.rk.hibernate.h_aop_pointcut.Aop"></bean> <!-- Aop配置 --> <aop:config> <!-- 【拦截所有public方法】 --> <!-- <aop:pointcut id="pt" expression="execution(public * *(..))"/> --> <!-- 【拦截所有save开头的方法 】 --> <!-- <aop:pointcut id="pt" expression="execution(* save*(..))"/> --> <!-- 【拦截指定类的指定方法, 拦截时候一定要定位到方法】 --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.h_aop_pointcut.UserDao.update(..))"/> --> <!-- 【拦截指定类的所有方法】 --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.h_aop_pointcut.UserDao.*(..))"/> --> <!-- 【拦截指定包,以及其自包下所有类的所有方法】 --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk..*.*(..))"/> --> <!-- 【多个表达式】 --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.h_aop_pointcut.UserDao.save(..) ) || execution(* com.rk.hibernate.h_aop_pointcut.OrderDao.save(..))"/> --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.h_aop_pointcut.UserDao.save(..) ) or execution(* com.rk.hibernate.h_aop_pointcut.OrderDao.save(..))"/> --> <!-- 下面2个且关系的,没有意义 --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.h_aop_pointcut.UserDao.save(..) ) && execution(* com.rk.hibernate.h_aop_pointcut.OrderDao.save(..))"/> --> <!-- <aop:pointcut id="pt" expression="execution(* com.rk.hibernate.h_aop_pointcut.UserDao.save(..) ) and execution(* com.rk.hibernate.h_aop_pointcut.OrderDao.save(..))"/> --> <!-- 【取非值】 注意:如果使用not,前面必须要有一个“空格”--> <!-- <aop:pointcut id="pt" expression="! execution(* com.rk.hibernate.h_aop_pointcut.UserDao.save(..))"/> --> <aop:pointcut id="pt" expression=" not execution(* com.rk.hibernate.h_aop_pointcut.UserDao.save(..))"/> <!-- 切面 --> <aop:aspect ref="aop"> <!-- 环绕通知 --> <aop:around method="around" pointcut-ref="pt"/> </aop:aspect> </aop:config> </beans>
IUserDao.java
package com.rk.hibernate.h_aop_pointcut; //接口 public interface IUserDao { void save(); void update(); }
UserDao.java
package com.rk.hibernate.h_aop_pointcut; /** * 目标对象 */ public class UserDao implements IUserDao { @Override public void save() { System.out.println("-----核心业务:保存!!!------"); // int a = 1/0; } @Override public void update() { System.out.println("-----核心业务:更新!!!------"); } }
OrderDao.java
package com.rk.hibernate.h_aop_pointcut; /** * 目标对象 * */ public class OrderDao { public void save() { System.out.println("-----核心业务:保存!!!------"); } }
Aop.java
package com.rk.hibernate.h_aop_pointcut; import org.aspectj.lang.ProceedingJoinPoint; public class Aop { public void point_cut() { } public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前...."); pjp.proceed(); // 执行目标方法 System.out.println("环绕后...."); } }
App.java
package com.rk.hibernate.h_aop_pointcut; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { private ApplicationContext ac = new ClassPathXmlApplicationContext("/com/rk/hibernate/h_aop_pointcut/applicationContext.xml"); @Test public void test() { // 目标对象有实现接口,spring会自动选择“JDK代理” IUserDao userDao = (IUserDao) ac.getBean("userDao"); System.out.println(userDao.getClass()); userDao.save(); userDao.update(); System.out.println(); System.out.println("----------------------------------------"); System.out.println(); // 目标对象没有实现接口, spring会用“cglib代理” OrderDao orderDao = (OrderDao) ac.getBean("orderDao"); System.out.println(orderDao.getClass()); orderDao.save(); } }
原文:http://lsieun.blog.51cto.com/9210464/1829082