Spring AOP概念
1)AOP(Aspect Oriented Programming)是面向切面编程。
就是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
简单说 就是在不改变方法原代码的基础上,对方法进行功能增强
本质上是生成了一个新的类,叫做代理类
(2)AOP对程序的扩展方式采用动态代理的方式. (JDK动态代理和Cglib动态代理两种方式)
Spring 动态代理
(1)JDK的动态代理
》Proxy类的方法
Proxy类的静态方法可以创建代理对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
》三个参数
参数1:ClassLoader loader 类加载器 , 用来加载代理对象
参数2:Class<?>[] interfaces 目标类的字节码对象数组. 因为代理的是接口,需要知道接口中所有的方法
参数3:InvocationHandler h 执行句柄, 代理对象处理的核心逻辑就在该接口中
案例:日志系统
给一个类的所有方法加log
Demo02
public class Demo02 {
public static void main(String[] args) {
Person p = new Person("jack","123456");
//生成代理类,创建该类对象
PersonDao2 personDao2 = new PersonDao2();
Logger logger = LoggerFactory.getLogger(PersonDao2.class);
ClassLoader classLoader=PersonDao2.class.getClassLoader();//与原来类一样
Class<?>[] interfaces=PersonDao2.class.getInterfaces();//与原来类一样
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用Dao类的update(person)
// 调用Logger类的debug(“update parameter return”)
//update delete add 的执行
//开始
long start = System.currentTimeMillis();
Object returnVal = method.invoke(personDao2,args);
long time = System.currentTimeMillis()-start;
logger.debug("方法名:"+method.getName()+" 参数"+ Arrays.toString(args)+" 返回值:"+returnVal+" 耗时"+time);
return returnVal;
}
};
IPersonDao2 personDao= (IPersonDao2) Proxy.newProxyInstance(classLoader,interfaces,handler);
// personDao.add(p);
personDao.update(p);
// personDao.delete(1);
}
}
PersonDao2
public class PersonDao2 implements IPersonDao2{
public void add(Person p){
System.out.println("执行 数据库的insert");
}
public void update(Person p){
System.out.println("执行 数据库的update");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void delete(int id){
System.out.println("执行 数据库的delete");
}
}
IPersonDao2
public interface IPersonDao2 {
void add(Person p);
void update(Person p);
void delete(int id);
}
动态代理JDK proxy
(1)动态代理,必须要有一个接口 com.wzx.demo01
(2)动态代理的三个参数
代理类,与被代理类 地位是一样的
(相同的ClassLoader,相同的接口)
所以,有相同的接口,相同的类加载器
(3)invoke方法
参2 表示要增强哪个方法
Object returnValue = method.invoke(laoZong,args);
AOP的术语
1、 目标类target:就是我们需要增强的那个类 LaoZong.class
2、 代理类proxy:就是自定义的代理的对象 $Proxy0.class
3、 连接点joinPoint:程序执行的某个特定位置,Spring仅支持方法的连接点
eat(),sleep(),run()
4、 切入点pointCut:就是在目标类中实际增强的方法
eat()
5、 织入weave:就是将代理类中需要增强的方法放入到目标类中去执行的过程
将原方法与其他类的方法一起调用
6、 引介Introduction:引介是一种特殊的增强,它为类添加一些属性和方法(课程不使用)
7、 通知advice:将代理对象中的方法应用到目标类的过程中产生的结果。
8、 切面aspect:所有的切入点和代理对象的方法组成在一起 构成了切面
AOP切面编程-切面表达式
(1)什么是切面表达式
execution([修饰符] 返回值类型 包.类.方法(参数列表) );
(2)切面表达式有什么用?
符合表达式的方法,会被增强
使用* 表过任意的内容
使用… 可以表示包与子包下面的类
使用…可以写在方法(…)表示任意参数
<!-- 配置他们的增强关系 生成一个代理类-->
<aop:config >
<aop:pointcut id="work" expression="execution(* com.wzx.service..*.*(..))"/>
<!-- 我想在work方法执行 之后调用一下writeLog-->
<aop:aspect ref="advice">
<aop:after method="writeLog" pointcut-ref="work"/>
</aop:aspect>
</aop:config>
AOP切面编程-增强方式
(1)增强方式的方式有哪些?
实质是增强的四个可选调用位置
(2)每个位置有四个对应的名称
(3)arround环绕
简化
joinPoint.proceed(); //切到原来的目标方法,进行执行
Advice
public class Advice {
public void writeLog(){
System.out.println("写一个开发备忘录");
}
public void before(){
System.out.println("before-------");
}
public void after(){
System.out.println("after-------");
}
public void afterReturn(){
System.out.println("afterReturn-------");
}
public void afterThrow(){
System.out.println("afterThrow-------");
}
}
applicationContext.xml
<!-- 配置他们的增强关系 生成一个代理类-->
<aop:config >
<aop:pointcut id="all" expression="execution( * com.wzx.service..*.*(..))"/>
<!-- 我想在work方法执行 之后调用一下writeLog-->
<aop:aspect ref="advice">
<!-- try-->
<aop:before method="before" pointcut-ref="all"/>
<!-- 有可能程序正常运行-->
<aop:after-returning method="afterReturn" pointcut-ref="all"/>
<!-- catch-->
<aop:after-throwing method="afterThrow" pointcut-ref="all"/>
<!-- finally-->
<aop:after method="after" pointcut-ref="all"/>
</aop:aspect>
</aop:config>
环绕通知
Advice
public void arround(ProceedingJoinPoint point ){//参目标类中的任意方法
try{
//执行before
before();
System.out.println("arround-------");
point.proceed();//对应你调用的UserImpl中的任意方法
//执行正常返回
afterReturn();
}catch (Throwable e){
//补救方法
afterThrow();
}finally {
//释放资源的方法
after();
}
}
applicationContext.xml
<!-- 配置他们的增强关系 生成一个代理类-->
<aop:config >
<aop:pointcut id="all" expression="execution( * com.wzx.service..*.*(..))"/>
<!-- 我想在work方法执行 之后调用一下writeLog-->
<aop:aspect ref="advice">
<aop:around method="arround" pointcut-ref="all"/>
</aop:aspect>
</aop:config>
AOP切面编程-注解***
(1)spring注解配置
一个xml开启注解自动代理
几个注解
切面@Aspect+四个注解 @Before @AfterReturning @AfterThrowing@After
切面@Aspect+@Arround
Advice
@Component
@Aspect
public class Advice {
public void writeLog(){
System.out.println("写一个开发备忘录");
}
//try{ }
// @Before("execution( * com.wzx.service..*.*(..))")
public void before(){
System.out.println("before-------");
}
//@AfterReturning("execution( * com.wzx.service..*.*(..))")
public void afterReturn(){
System.out.println("afterReturn-------");
}
//catch(exception e){ }
// @AfterThrowing("execution( * com.wzx.service..*.*(..))")
public void afterThrow(){
System.out.println("afterThrow-------");
}
//finally
// @After("execution( * com.wzx.service..*.*(..))")
public void after(){
System.out.println("after-------");
}
@Around("execution( * com.wzx.service..*.*(..))")
public void arround(ProceedingJoinPoint point ){//参目标类中的任意方法
try{
//执行before
before();
System.out.println("arround-------");
point.proceed();
//执行正常返回
afterReturn();
}catch (Throwable e){
//补救方法
afterThrow();
}finally {
//释放资源的方法
after();
}
}
}
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: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:component-scan base-package="com.wzx.service"/>
<!--开启自动AOP代理-->
<aop:aspectj-autoproxy/>
</beans>