Aop思想
- servlet技术中的filter过滤器技术
- struts2中的interceptor技术
- 动态代理
spring-aop开发概念
spring封装了代理技术来体现aop思想.
spring可以对所有类进行代理.
spring为了能够对所有类进行代理.封装了两种代理技术
动态代理
局限性:被带代理对象必须实现至少一个接口.动态代理技术是基于接口的代理技术
没有实现接口那么无法被动态代理.
CGLib代理
属于继承代理.该技术生成的代理类是被代理类的子类. 几乎所有类都可以被CGLIb代理.处了被final修饰的类.
有关aop的名词解释
连接点(join point): 所有可以被增强(代理)的方法
切点(point cut):即将(需要)或已经被增强的方法
通知(advice):对切点需要增强的代码
目标对象(target):被代理的对象
代理对象(proxy):对目标对象的切点应用通知后生成的对象
织入(weaver)动词:将通知应用到切点的过程,或者说生成代理对象的过程
切面:(aspect|advisor)组合词:切点+通知 称之为切面
aop在spring中的配置
使用xml配置文件开发
- 导包
4+2包+spring-aop包+spring-aspects包 2个在spring辅助包中:aop联盟包+aspectj-weaver包
- 目标对象
- 通知(对切点需要增强的代码,一个类)
前置通知 通知代码,在目标方法执行前调用
环绕通知 通知代码,在目标方法执行前和执行后都调用
后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知不执行
后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知仍然执行
异常通知 通知代码,在目标方法抛出异常后才会执行.
- 配置
1.导入aop约束,前缀为aop
2.注册目标对象,注册通知对象
3.在xml中配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<!-- 1.配置目标对象 -->
<bean name="userService" class="cn.xiaos.service.UserServiceImpl" ></bean>
<!-- 2.配置通知对象 -->
<bean name="myAdvice" class="cn.xiaos.advice.MyAdvice" ></bean>
<!-- 3.配置切面 切点+通知 -->
<!-- 3.1 书写切点表达式,aspectJ切点表达式
格式 : execution(表达式)
public void cn.itcast.service.UserServiceImpl.save()
void cn.itcast.service.UserServiceImpl.save() 同上
* cn.itcast.service.UserServiceImpl.save() 方法返回值任意
* cn.itcast.service.*ServiceImpl.save() 包中所有以ServiceImpl结尾的类
* cn.itcast.service.*ServiceImpl.*() 方法名任意
* cn.itcast.service.*ServiceImpl.*(..) 没有或多个任意参数
* cn.itcast.service..*ServiceImpl.*(..) 当前包以及后代包
-->
<aop:config>
<!--
aop:pointcut : 配置切点(需要被增强的方法)
expression:表达式
id:为表达式指定名称,方便后续引用
-->
<aop:pointcut expression="execution(* cn.xiaos.service.*ServiceImpl.*(..))" id="myPC"/>
<!-- 配置通知+切点 => 切面
ref:哪个对象是通知类
-->
<aop:aspect ref="myAdvice" >
<!-- 前置通知 method=>方法名 pointcut-ref=>切点名称 -->
<aop:before method="before" pointcut-ref="myPC" />
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="myPC" />
<!-- 后置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="myPC" />
<!-- 后置通知 -->
<aop:after method="after" pointcut-ref="myPC" />
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="myPC" />
</aop:aspect>
</aop:config>
</beans>
使用注解方式配置
1.导包(同上),2.目标文件编写(同上)3.注册目标对象,注册通知对象
3.开启aop注解配置事务开关
<aop:aspectj-autoproxy> </aop:aspectj-autoproxy>
4.在通知类中使用注解配置切面
package cn.xiaos.advice;
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;
// 5种通知
// 前置通知 通知代码,在目标方法执行前调用
// 环绕通知 通知代码,在目标方法执行前和执行后都调用
// 后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知不执行
// 后置通知 通知代码,在目标方法执行后调用. 切点方法抛出异常,通知仍然执行
// 异常通知 通知代码,在目标方法抛出异常后才会执行.
//通知类
//@Aspect => 标识当前类用于配置切面
@Aspect
public class MyAdvice {
@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")
public void myPC(){}
// 前置通知
@Before("MyAdvice.myPC()")
public void before() {
System.out.println("我是前置通知!");
}
// 环绕通知
@Around("MyAdvice.myPC()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("我是环绕通知前半部分,我在切点方法执行前执行!");
// 手动调用切点方法执行
Object obj = pjp.proceed(); // 执行切点方法
System.out.println("我是环绕通知后半部分,我在切点方法执行后执行!");
return obj;
}
// 后置通知 => 出现异常,就不执行
@AfterReturning("MyAdvice.myPC()")
public void afterReturning() {
System.out.println("我是后置通知,出现异常不执行!");
}
// 后置通知 => 出现异常,仍然执行
@After("MyAdvice.myPC()")
public void after() {
System.out.println("我是后置通知,出现异常仍然执行!");
}
// 异常通知
@AfterThrowing("MyAdvice.myPC()")
public void afterThrowing() {
System.out.println("我是异常通知,抛出异常后执行!");
}
}