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