什么是AOP
AOP是一种能在程序运行时,将我们的横切性关注点方法动态的织入到指定类的指定方法上,对我们的目标方法在执行前后进行代码增强,这就是面向切面的编程思想,是对传统的面向对象的一种补充。Spring的AOP分为静态AOP和动态的AOP,Spring底层为动态AOP提供了两种实现方法,jdk动态代理和cglib代理,其中jdk动态代理是基于接口实现的,而cglib代理是基于继承实现的。虽然这两种代理在实现方式上略有不同,但其本质都是使用代理模式,为目标类生成代理对象,通过代理对象在调用目标方法的前后做一些额外的操作,从而实现我们目标方法的增强。
手动编写代理
在之前我们要为一个类生成代理对象,需要自己手动编写代码来实现,具体是通过Proxy.newProxyIntance()来返回代理类的代理对象,其中传入的参数有三个,第一个是代理类对象,第二个是代理类所实现的接口,第三个是一个InvocationHandler类型的对象,在这个对象中有一个invoke()方法,这个方法的具体作用就是代理要做的事情。下面来看看具体的实现。
首先需要准备四个类:接口、接口实现、代理类以及测试类
1、创建接口
public interface UserService {
public void insert();//插入用户
}
2、创建接口实现类
public class UserServiceImpl implements UserService{
@Override
public void insert() {
System.out.println("do insert......");
}
}
3、创建生成代理的类
public class UserProxy implements InvocationHandler{
private Object object;//目标对象
public UserProxy(Object obj){
object=obj;
}
public Object getProxyIntance(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);//返回代理对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打开事务");
Object invoke = method.invoke(object, args);//代理类调用真正的方法
System.out.println("关闭事务");
return invoke;
}
}
4、测试类
public class ProxyTest {
public static void main(String[] args) {
UserService userService=new UserServiceImpl();
UserProxy userProxy = new UserProxy(userService);//将代理对象传递进去
UserService intance = (UserService) userProxy.getProxyIntance();//获得代理对象
intance.insert();//这里调用的只是代理对象中的方法,真正的方法是在代理对象内部代用的
}
}
运行结果:
Spring AOP实现代码增强
首先spring aop实现代码增强的本质上也是通过代理来实现的,使用aop来实现代理就不用我们自己手动编写像上述那样的代理类了。只需通过简单的配置或者注解声明的方法就能为我们的目标方法进行代码增强,其底层对自动根据我们的目标类来决定使用jdk动态代理还是cglib代理。
aop中的相关名词解释
1、join point:连接点,所有能用来增强的方法
2、point cut:切入点,想要增强的方法
3、advice:通知(增强),为我们的目标方法的额外操作的方法
4、waving:织入,将我们的通知织入到切入点的动作
5、aspect:切面,通知+切入点
spring aop中提供了五种通知的类型,在四种通知类型会在我们的目标方法调用时,在不同的时机进行自动调用从而增强目标方法 的功能。
1、前置通知:目标方法执行前执行
2、环绕通知:目标方法执行前后执行,需要在此通知中手动调用我们的目标方法。
3、后置通知:目标方法执行后执行,出现异常则不会调用
4、异常通知:目标方法执行过程中有异常则执行
5、最终通知:在目标方法调用后,无论如何都会执行
下面进行案例演示:
1、接口及接口实现类
public interface UserService {
public void insert();
}
public class UserServiceImpl implements UserService {
@Override
public void insert() {
System.out.println("insert is running.......");
//int a=1/0;
}
}
2、增强类
public class MyAdvice {
//前置通知
public void before(){
System.out.println("前置通知:开启事务");
}
//后置通知,出现异常时不会执行
public void after(){
System.out.println("后置通知:关闭事务");
}
//出现异常时执行
public void throwing(){
System.out.println("异常通知:出现异常啦");
}
//环绕通知
public Object arount(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知前部分");
Object proceed = pjp.proceed();//调用目标方法
System.out.println("环绕通知后部分");
return proceed;
}
//最终通知,目标方法执行后无论如何都会执行
public void finaled(){
System.out.println("最终通知:关闭资源部");
}
}
3、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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置目标类 -->
<bean class="SpringAopTest.UserServiceImpl" id="userService"></bean>
<!-- 配置增强类 -->
<bean class="SpringAopTest.MyAdvice" id="myAdvice"></bean>
<!-- 织入的过程,将增强切入到指定的切入点中 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* SpringAopTest.UserServiceImpl.insert())" id="pc"/>
<!-- 配置切面 -->
<aop:aspect ref="myAdvice">
<!-- 前置通知 -->
<aop:before method="before" pointcut-ref="pc"/>
<!-- 异常通知-->
<aop:after-throwing method="throwing" pointcut-ref="pc"/>
<!-- 最终通知 :无论是否出现异常都执行-->
<aop:after method="finaled" pointcut-ref="pc"/>
<!-- 后置通知:出现异常不执行 -->
<aop:after-returning method="after" pointcut-ref="pc"/>
<!-- 环绕通知 -->
<aop:around method="arount" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>
4、测试类
public class AopTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringAopTest/ApplicationContent.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.insert();
}
}
5、执行结果