Spring框架AOP增强,动态代理
为什么需要AOP
AOP全名(Aspect-oriented programming)面向切面编程大法,它有很多兄弟,分别是经常见的面向对象编程,朴素的面向过程编程和神秘的函数式编程等。
AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理。本文就主要讲解AOP的基本术语,最后介绍一下AOP的两种代理方式:
(1)以AspectJ为代表的静态代理。
(2)以Spring AOP为代表的动态代理。
AOP的基本概念
AOP:面向切面编程,不修改源代码的基础上对代理对象的功能进行增强,要指定增强位置配置该位置做的事情
1.切面(Aspest)
一个切面能够包含同一个类型的不同增强方法.切面由切入点和通知组成,它既包含了横切逻辑的定义,也包括了切入点的定义。 Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中,(使用 @Aspect 注解的类就是切面)。
2.目标对象(Target)
目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。
3. 连接点(JoinPoint)
程序执行过程中明确的点,连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。
4.增强处理
Advisor是切面的另外一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。
5.切入点(PointCut)
切入点是对连接点进行拦截的条件定义。
深入理解AOP增强
1.导入所需的jar包
2.分层结构
3.创建一个类,这个类完成核心功能。
(1)创建接口
package com.xue.service;
/*
* 演员接口
* */
public interface Actor {
//唱
void sing();
//跳
void dance();
//rap
void rap();
//篮球
void baskball();
}
(1)实现接口
package com.xue.service.Impl;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import com.xue.service.Actor;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
public class IKUN implements Actor {
@Override
public void sing() {
System.out.println("只因你太美");
}
@Override
public void dance() {
System.out.println("迎面走来的你");
}
@Override
public void rap() {
System.out.println("让我如此蠢蠢欲动");
}
@Override
public void baskball() {
System.out.println("这种感觉我从未有");
}
}
这个类可以被其他类实例化,并调用实现的方法。
4.创建Loger类,用来做功能的增强。
package com.xue.logger;
public class Logger {
public void beforePrintLog(){
System.out.println("前置通知:beforePrintLog执行...");
}
public void afterReturningPrintLog(){
System.out.println("后置通知:afterReturningPrintLog执行...");
}
public void afterThrowingPrintLog(){
System.out.println("异常通知:afterThrowingPrintLog执行...");
}
public void afterPrintLog(){
System.out.println("最终通知:afterPrintLog执行...");
}
}
这个类可以被其他类实例化,并调用其中的方法。通常这些方法会在AOP编程中被调用,用于给程序添加额外的功能或行为。
5.配置Spring的AOP核心配置
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="logger" class="com.xue.logger.Logger"/>
<bean id="ikun" class="com.xue.service.Impl.IKUN"/>
<aop:config>
<aop:aspect id="xxs" ref="logger">
<aop:before method="beforePrintLog" pointcut="execution(void com.xue.service.Impl.IKUN.sing())"/>
<aop:after-returning method="afterReturningPrintLog" pointcut="execution(void com.xue.service.Impl.IKUN.dance())"/>
<!-- 定义了一个名为afterThrowingPrintLog的方法,使用了切入点表达式execution(* *..CxkServiceImpl.*(..)) -->
<aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(void com.xue.service.Impl.IKUN.rap())"/>
<aop:after method="afterPrintLog" pointcut="execution(* *..ikun.baskball(..))"/>
</aop:aspect>
</aop:config>
</beans>
6.测试方法
package com.xue.servlet;
import com.xue.service.Actor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test02 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Actor actor =context.getBean(Actor.class);
actor.sing();
actor.rap();
actor.dance();
actor.baskball();
}
}
深入理解动态代理
在Java开发中如果一个类中的方法在基本功能之外需要进行功能扩充或者功能增强,如:事务控制、权限判断、日志记录等等操作,此时可以使用动态代理机制。
Java的JDK中Proxy类可以实现基于接口的动态代理,实现步骤示例如下:
1.因为Proxy类必须基于接口进行动态代理,所以首先创建接口,定义接口的规范,即功能方法的定义。
package com.xue.service;
public interface BookService {
//音乐表演
void musicAct(int money);
//舞蹈表演
void danceAct(int money);
//娱乐表演
void yueLeAct(int money);
}
2.定义实现接口的子类,实现接口定义的方法,此方法只需要把核心功能实现即可,其他增强的操作可以在代理类中实现。
package com.xue.service.Impl;
import com.xue.service.BookService;
public class BookServiceImpl implements BookService {
@Override
public void musicAct(int money) {
System.out.println("音乐表演");
}
@Override
public void danceAct(int money) {
System.out.println("舞蹈表演");
}
@Override
public void yueLeAct(int money) {
System.out.println("娱乐表演");
}
}