AOP概念
l AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
l 经典应用:事务管理、性能监视、安全检查、缓存 、日志等
l Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
l AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
Aop的实现原理
l aop底层将采用代理机制进行实现。
专业术语
1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。
1.execution() 用于描述方法 【掌握】
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
包,[省略]
com.itheima.crm 固定包
com.itheima.crm.*.service crm包下面子包任意 (例如:com.itheima.crm.staff.service)
com.itheima.crm.. crm包下面的所有子包(含自己)
com.itheima.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
UserServiceImpl 指定类
*Impl 以Impl结尾
User* 以User开头
* 任意
方法名,不能省略
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
(参数)
() 无参
(int) 一个整型
(int ,int) 两个
(..) 参数任意
throws ,可省略,一般不写。
2.within:匹配包或子包中的方法(了解)
within(com.itheima.aop..*)
3.this:匹配实现接口的代理对象中的方法(了解)
this(com.itheima.aop.user.UserDAO)
4.target:匹配实现接口的目标对象中的方法(了解)
target(com.itheima.aop.user.UserDAO)
5.args:匹配参数格式符合标准的方法(了解)
args(int,int)
6.bean(id) 对指定的bean所有的方法(了解)
bean('userServiceId')
=======================================================================================
实例 :AOP基于xml配置开发
UserAOP.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" 5 http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop.xsd"> 9 10 <bean id="aspectUser" class="com.spring_aop1.AspectUser"></bean> 11 <bean id="user" class="com.spring_aop1.User"></bean> 12 13 <aop:config> 14 <!-- expression="execution(返回值 包名.类名.方法名(参数类型)) id="任意":切入点名 --> 15 <aop:pointcut expression="execution(* com.spring_aop1.*.*(..))" id="myPointcut"/> 16 17 <aop:aspect ref="aspectUser"> 18 <aop:before method="password" pointcut-ref="myPointcut"/> 19 <aop:after-returning method="after" pointcut-ref="myPointcut" returning="obj"/> 20 <!-- <aop:around method="around" pointcut-ref="myPointcut" /> --> 21 <aop:around method="aroundR" pointcut-ref="myPointcut" /> 22 23 <aop:after-throwing method="throwable" pointcut-ref="myPointcut" throwing="e"/> 24 </aop:aspect> 25 26 </aop:config> 27 28 </beans>
User.java
1 package com.spring_aop1; 2 3 public class User { 4 5 private String str; 6 7 public String getStr() { 8 return str; 9 } 10 public void setStr(String str) { 11 this.str = str; 12 } 13 14 15 public void insert(){ 16 System.out.println("insert====ok"); 17 } 18 public void delete(){ 19 System.out.println("delete====ok"); 20 } 21 public void update(){ 22 System.out.println("update====ok"); 23 } 24 public void selete(){ 25 System.out.println("insert====ok"); 26 } 27 28 }
AspectUser.java
1 package com.spring_aop1; 2 3 import org.aspectj.lang.JoinPoint; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 6 public class AspectUser { 7 8 /** 9 * 定义一个前置通知 10 * */ 11 public void password(){ 12 System.out.println("前置通知:密码验证=====成功"); 13 } 14 15 /** 16 * 定义一个后置通知(可得方法返回值) 17 * @param jp execution(void com.spring_aop.User.save()) 18 * @param obj 19 * */ 20 public void after(JoinPoint jp,Object obj){ 21 String name = jp.getSignature().getName(); 22 23 System.out.println("后置通知:after获取一个返回值类型====切入点"); 24 System.out.println("after返回值信息为:"+name); 25 } 26 27 /** 28 * 定义一个环绕通知 29 * @param pjp execution(void com.spring_aop.User.save()) 30 * */ 31 public void around(ProceedingJoinPoint pjp) throws Throwable{ 32 System.out.println("环绕通知:around执行环绕通知前执行"); 33 pjp.proceed(); 34 System.out.println("环绕通知:around执行环绕通知后执行"); 35 } 36 /** 37 * 定义一个环绕通知(可得方法返回值) 38 * @throws Throwable 39 * */ 40 public Object aroundR(ProceedingJoinPoint pjp) throws Throwable{ 41 System.out.println("环绕通知:around执行环绕通知前执行"); 42 Object obj = pjp.proceed(); 43 System.out.println("环绕通知:around执行环绕通知后执行"); 44 45 String s = pjp.getSignature().getName(); 46 System.out.println("around返回值的类型:"+obj+" around返回方法名:"+s); 47 return obj; 48 } 49 50 /** 51 * 定义一个异常通知(可得方法返回值) 52 * @throws Throwable 53 * */ 54 public void throwable(JoinPoint jp,Throwable e){ 55 System.out.println("到我这里来,说明 你发生了异常======"); 56 } 57 58 }
Test.java
1 package com.spring_aop1; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class UserTest { 7 8 public static void main(String[] args) { 9 10 String str = "com/spring_aop1/UserAop.xml"; 11 ApplicationContext context = new ClassPathXmlApplicationContext(str); 12 13 User user = (User)context.getBean("user"); 14 user.insert(); 15 16 } 17 18 }
实例 :AOP基于注解开发
UserAOP.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" 6 http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/aop 9 http://www.springframework.org/schema/aop/spring-aop.xsd 10 http://www.springframework.org/schema/context 11 http://www.springframework.org/schema/context/spring-context.xsd"> 12 13 <!-- 自动扫描 配置 扫描所有注解 :使用注解注入 --> 14 <context:component-scan base-package="com.spring_aop2"></context:component-scan> 15 16 <!-- 添加AOP的注解扫描 --> 17 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 18 19 20 </beans>
User.java
1 package com.spring_aop2; 2 3 import org.springframework.stereotype.Component; 4 5 @Component(value="user") 6 public class User { 7 8 private String str; 9 10 public String getStr() { 11 return str; 12 } 13 public void setStr(String str) { 14 this.str = str; 15 } 16 17 public void insert(){ 18 System.out.println("insert====ok"); 19 } 20 public void delete(){ 21 System.out.println("delete====ok"); 22 } 23 public void update(){ 24 System.out.println("update====ok"); 25 int i = 1/0; 26 } 27 public void selete(){ 28 System.out.println("insert====ok"); 29 } 30 31 }
AspectUser.java
1 package com.spring_aop2; 2 3 import org.aspectj.lang.JoinPoint; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 import org.aspectj.lang.annotation.After; 6 import org.aspectj.lang.annotation.AfterReturning; 7 import org.aspectj.lang.annotation.AfterThrowing; 8 import org.aspectj.lang.annotation.Around; 9 import org.aspectj.lang.annotation.Aspect; 10 import org.aspectj.lang.annotation.Before; 11 import org.aspectj.lang.annotation.Pointcut; 12 import org.springframework.stereotype.Component; 13 14 @Component("aspectUser") //组件 15 @Aspect //声明这是一个切面类 16 public class AspectUser { 17 18 /** 19 * <aop:pointcut 20 * expression="execution(* com.spring_aop2.*.*(..))" 21 * id="myPointcut" /> 22 * */ 23 @Pointcut("execution(* com.spring_aop2.*.*(..))") 24 private void myPoint(){} 25 26 /** 27 * 定义一个前置通知 28 * */ 29 @Before("execution(* com.spring_aop2.*.*(..))") //指向切入点的Id(私有方法的方法名) 30 public void password(){ 31 System.out.println("前置通知:密码验证=====成功"); 32 } 33 34 /** 35 * 定义一个后置通知(可得方法返回值) 36 * @param jp execution(void com.spring_aop.User.save()) 37 * @param obj 38 * */ 39 @AfterReturning(value="myPoint()",returning="obj") 40 public void after(JoinPoint jp,Object obj){ 41 String name = jp.getSignature().getName(); 42 43 System.out.println("后置通知:获取一个返回值类型====切入点"); 44 System.out.println("after返回值信息为:"+name); 45 } 46 47 /** 48 * 定义一个环绕通知 49 * @param pjp execution(void com.spring_aop.User.save()) 50 * */ 51 @Around("execution(* com.spring_aop.*.*(..))") 52 public void around(ProceedingJoinPoint pjp) throws Throwable{ 53 System.out.println("环绕通知:around执行环绕通知前执行"); 54 pjp.proceed(); 55 System.out.println("环绕通知:around执行环绕通知后执行"); 56 } 57 /** 58 * 定义一个环绕通知(可得方法返回值) 59 * @throws Throwable 60 * */ 61 public Object aroundR(ProceedingJoinPoint pjp) throws Throwable{ 62 System.out.println("环绕通知:around执行环绕通知前执行"); 63 Object obj = pjp.proceed(); 64 System.out.println("环绕通知:around执行环绕通知后执行"); 65 66 String s = pjp.getSignature().getName(); 67 System.out.println("around返回值的类型:"+obj+" around返回方法名:"+s); 68 return obj; 69 } 70 71 /** 72 * 定义一个异常通知(可得方法返回值) 73 * @throws Throwable 74 * */ 75 @AfterThrowing(value="myPoint()",throwing="e") 76 public void throwable(JoinPoint jp,Throwable e){ 77 System.out.println("到我这里来,说明 你发生了异常======"); 78 } 79 80 }
Test.java
1 package com.spring_aop2; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class UserTest { 7 8 public static void main(String[] args) { 9 10 String str = "com/spring_aop2/UserAop.xml"; 11 12 ApplicationContext context = new ClassPathXmlApplicationContext(str); 13 14 User user = (User)context.getBean("user"); 15 user.insert(); 16 //user.update(); 17 18 19 } 20 21 }