> 文章列表 > Spring 04 -SpringAOP开发

Spring 04 -SpringAOP开发

Spring 04 -SpringAOP开发

SpringAOP开发

  • SpringAOP
    • 1 原理
    • 2 动态代理
      • 2.1 JDK动态代理
      • 2.2.2 Cglib动态代理
      • 2.2.3 JDK动态代理和Cglib动态代理
    • 3 SpringAOP
      • 3.1 AOP专业术语
      • 3.2 环境搭建
      • 3.3 基于XML配置
      • 3.4 基于注解配置
      • 2.5 通知类型

面向切面编程,在不修改源代码的情况加,对类功能实现增强


SpringAOP

1 原理

AOP原理
Spring 04 -SpringAOP开发

2 动态代理

Spring的底层技术就是动态代理

  • 动态代理分类
    • JDK动态代理
    • Cglib动态代理

2.1 JDK动态代理

接口:定义代理对象和被代理对象需要做的事情

//定义代理类和被代理类共同做的事情
public interface Subject {void saleHouse();
}

实现类:目标对象(被增强对象)

public class RealSubject implements Subject{@Overridepublic void saleHouse() {System.out.println("买房子....");}
}

代理工厂

public class JDKProxyFactory {/* 使用jdk动态代理,获取代理对象* @param obj   被代理对象* @return      代理对象*/public static Object getProxy(Object obj){//类加载器ClassLoader classLoader = JDKProxyFactory.class.getClassLoader();//被代理对象所实现的接口Class<?>[] interfaces = obj.getClass().getInterfaces();//对对象的方法调用的拦截InvocationHandler invocationHandler = new InvocationHandler() {/ @param proxy             代理对象* @param method            拦截方法* @param args              拦截方法的参数* @return                  返回的是该方法的返回值*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//做增强工作System.out.println("找客户。。。。");Object invoke = method.invoke(obj, args);System.out.println("办手续。。。。");return invoke;}};Object proxyInstance = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);return proxyInstance;}
}

测试

@Test
public void test01(){//通过代理工厂获取代理对象,通过代理对象调用方法Subject proxy = (Subject) JDKProxyFactory.getProxy(new RealSubject());proxy.saleHouse();//说明代理对象不属于RealSubject类,而是Subject接口的实现类System.out.println(proxy instanceof RealSubject); //false
}

2.2.2 Cglib动态代理

类:目标对象(被增强对象) 不需要实现接口

public class RealSubject{public void saleHouse() {System.out.println("买房子....");}
}

动态代理工厂

public class CglibProxyFactory {public static Object getProxy(Object obj){//创建Cglib代理工具类对象Enhancer enhancer = new Enhancer();//设置代理对象的父类(代理对象和被代理对象是继承关系)enhancer.setSuperclass(obj.getClass());Callback callback = new MethodInterceptor() {/ @param o                代理对象* @param method           拦截的方法* @param objects          拦截的方法参数* @param methodProxy      方法的代理对象* @return                 方法的返回值* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//做增强工作System.out.println("找客户cglib。。。。");Object invoke = method.invoke(obj, objects);System.out.println("办手续cglib。。。。");return invoke;}};//拦截被代理对象的方法enhancer.setCallback(callback);//创建代理对象Object o = enhancer.create();return o ;}
}

测试

 @Test
public void test02(){//被代理对象RealSubject realSubject = new RealSubject();//通过代理工厂获取代理对象,通过代理对象调用方法//代理对象RealSubject proxy = (RealSubject) CglibProxyFactory.getProxy(realSubject);proxy.saleHouse();//说明代理对象属于RealSubject类,而且就是RealSubject类的子类System.out.println(proxy instanceof RealSubject); //true
}

2.2.3 JDK动态代理和Cglib动态代理

JDK动态代理和Cglib动态代理

  • 两者都可以实现产生代理对象
  • JDK动态代理是java原生自带的,Cglib动态代理是第三方的
  • JDK动态代理实现代理:代理对象和目标对象之间实现同一个接口
  • Cglib动态代理实现代理:代理对象是目标对象的子类

3 SpringAOP

3.1 AOP专业术语

  • 连接点(Joinpoint): 表示一切能被增强方法
  • 切入点(Pointcut): 被增强的方法 <aop:pointcut id="pc" expression="execution(* com.ying.service..*.*(..))"/>
  • 通知、增强(Advice): 增强的功能(通知的类型:前置通知、后置通知、异常通知、最终通知、环绕通知) <aop:before method="before" pointcut-ref="pc"/>
  • 目标对象(Target): 被代理对象
  • 织入(Weaving): 将通知加入连接点的过程 aop:aspect ref=""里面的代码过程
  • 代理(Proxy): 代理对象
  • 切面(Aspect): 连接点被增强的内容称之为切面(切入点+通知) aop:aspect ref=""

3.2 环境搭建

导入依赖 spring-aspects

<!-- springAOP切面开发的依赖  -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.6</version>
</dependency>

3.3 基于XML配置

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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 开启注解扫描 --><context:component-scan base-package="com.ying.aop"/><!-- SpringAOP的配置   --><!-- 创建增强类   --><bean id="advice" class="com.ying.advice.MyAdvice"></bean><aop:config><!-- SpringAOP的切面   --><aop:aspect ref="advice"><!-- SpringAOP切入点 id:切入点的唯一标识   expression:切入点表达式 --><!--切入点表达式方法的全称public void com.ying.service.impl.UserServiceImpl.addUser();* com.ying.service.impl.UserServiceImpl.addUser();* com.ying.service..*.*(..);* com.ying.service.*.*Impl.*();--><aop:pointcut id="pc" expression="execution(* com.ying.service..*.*(..))"/><!-- SpringAOP的通知配置  --><!-- <aop:before method="before" pointcut-ref="pc"></aop:before>--><!-- <aop:after method="after" pointcut-ref="pc"></aop:after>--><!-- <aop:after-throwing method="throwing" pointcut-ref="pc"/>--><!-- <aop:after-returning method="returning" pointcut-ref="pc"/>--><aop:around method="around" pointcut-ref="pc"></aop:around></aop:aspect></aop:config>
</beans>

增强(通知)类

//增强类
public class MyAdvice {//    public void before(){
//        System.out.println("前置通知(在目标对象的方法之前执行)");
//    }
//    public void after(){
//        System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
//    }
//    public void throwing(){
//        System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
//    }
//    public void returning(){
//        System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
//    }public Object around(ProceedingJoinPoint joinPoint){try {System.out.println("前置通知(在目标对象的方法之前执行)");//System.out.println("方法本身");//执行目标对象的方法Object o = joinPoint.proceed();//获取到目标对象Object target = joinPoint.getTarget();System.out.println(target);//获取目标对象的方法Signature signature = joinPoint.getSignature();System.out.println(signature.getName());System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");//通过调用目标对象的方法获取到返回值,并继续返回return o;} catch (Throwable e) {e.printStackTrace();System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");} finally {System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");}return null;}
}

测试 依赖 spring-test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {@Autowiredprivate UserService userService;@Testpublic void test01(){int count = userService.addUser();System.out.println(count);//userService.deleteUser();}
}

结果

前置通知(在目标对象的方法之前执行)
addUser...
com.ying.service.impl.UserServiceImpl@543588e6
addUser
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))
100

3.4 基于注解配置

xml配置文件

<!-- 开启注解扫描 -->
<context:component-scan base-package="com.ying"/>
<!-- 开启AOP的注解扫描   -->
<aop:aspectj-autoproxy/>

增强类

@Component
@Aspect   //设置为切面
public class MyAdvice2 {@Pointcut("execution(* com.ying.service..*.*(..))")public void pc(){}@Before("pc()")public void before(){System.out.println("前置通知(在目标对象的方法之前执行)");}@After("execution(* com.ying.service..*.*(..))")public void after(){System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");}@AfterThrowing("execution(* com.ying.service..*.*(..))")public void throwing(){System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");}@AfterReturning("execution(* com.ying.service..*.*(..))")public void returning(){System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");}//    @Around("execution(* com.ying.service..*.*(..))")
//    public Object around(ProceedingJoinPoint joinPoint){
//        try {
//            System.out.println("前置通知(在目标对象的方法之前执行)");
//            //System.out.println("方法本身");
//            //执行目标对象的方法
//            Object o = joinPoint.proceed();
//            //获取到目标对象
//            Object target = joinPoint.getTarget();
//            System.out.println(target);
//            //获取目标对象的方法
//            Signature signature = joinPoint.getSignature();
//            System.out.println(signature.getName());
//            System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
//            //通过调用目标对象的方法获取到返回值,并继续返回
//            return o;
//        } catch (Throwable e) {
//            e.printStackTrace();
//            System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
//        } finally {
//            System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
//        }
//        return null;
//    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class AOPTest {@Autowiredprivate UserService userService;@Testpublic void test01(){userService.deleteUser();}
}

结果

前置通知(在目标对象的方法之前执行)
deleteUser...
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))

2.5 通知类型

  • 环绕通知
    • public Object around(ProceedingJoinPoint joinPoint){}
    • 调用目标对象的方法joinPoint.proceed();
  • 四种通知:
    • 前置通知【在调用目标方法之前执行】(开启事务)
    • 最终通知【在调用目标方法之后执行(无论是否有错都会执行)】(释放资源)
    • 异常通知【在调用目标方法报错执行】(回滚事务)
    • 后置通知【在调用目标方法之后执行】(提交事务)