Spring AOP 的 代理模式

AOP:面向切面编程

Spring 的 动态代理模式有两种: JDK动态代理和 CGLIB动态代理。

JDK动态代理:通过 java.lang.reflect.Proxy类实现的,必须实现一个或多个接口,代码实现。

CGLIB动态代理:不需要实现接口,底层通过使用字节码处理框架ASM转换字节码,并生成新的类。

目前流行的AOP框架有两种  Spring AOP 和 AspectJ

Spring AOP :使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类植入增强的代码。
AspectJ :是一个基于 Java 语言的 AOP 框架,从 Spring 2.0 开始,Spring AOP 引入了对 AspectJ 的支持。AspectJ 扩展了 Java 语言,提供了一个专门的编译器,在编译时提供横向代码的植入。

Spring AOP开发AOP:

声明式可以选择性使用 JDK和CGLIB

<!--true:使用cglib; false :使用jdk动态代理-->
<property name="proxyTargetClass" value="true" />

AspectJ开发AOP两种方式:

基于 XML 的声明式。
基于 Annotation 的声明式。

一下代码逐一举例-------------------

JDK动态代理:

1、创建业务类接口 CustomerService 以及业务类实现类 CustomerServiceImpl;

package com.woo.service;

public interface CustomerService {
    //crud
    void create();

    void retrieve();

    void update();

    void delete();
}
package com.woo.service.impl;

import com.woo.service.CustomerService;

public class CustomerServiceImpl implements CustomerService {

    @Override
    public void create(){
        System.out.println("create----");
    }
    @Override
    public void retrieve(){
        System.out.println("retrieve----");
    }
    @Override
    public void update(){
        System.out.println("update----");
    }
    @Override
    public void delete(){
        System.out.println("delete-----");
    }
}

2、创建切面类:MyAspect,写增强方法 myBefore ,myAfter;

package com.woo.service.impl;

public class MyAspect {

    public void myBefore(){
        System.out.println("before");
    }

    public void myAfter(){
        System.out.println("after");
    }
}

3、创建代理类:MyFactory 

package com.woo.factory;

import com.woo.service.CustomerService;
import com.woo.service.impl.CustomerServiceImpl;
import com.woo.service.impl.MyAspect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyFactory {

    public static CustomerService getBean() {
        //准备目标类
        final CustomerService customerService = new CustomerServiceImpl();
        //创建切面类实例,用于调用切面类中相应的方法
        final MyAspect myAspect = new MyAspect();
        //使用代理,进行增强
        return (CustomerService) Proxy.newProxyInstance(
                MyFactory.class.getClassLoader(),//当前类的类加载器
                new Class[]{CustomerService.class},//所创建实例的实现类的接口
                new InvocationHandler() {//需要增强的方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        myAspect.myBefore();//前增强
                        Object obj = method.invoke(customerService,args);
                        myAspect.myAfter();
                        return obj;
                    }
                }
        );
    }
}

4、测试

 @Test
 public void test3(){
     //从工厂获取指定的内容,
     CustomerService customerService = MyFactory.getBean();
     //执行方法
     customerService.create();
     customerService.retrieve();
     customerService.update();
     customerService.delete();
 }

5、输出:

CGLIB动态代理:

1、创建业务类 CustomerServiceImpl;

package com.woo.service.impl;

import com.woo.service.CustomerService;

public class CustomerServiceImpl implements CustomerService {

    @Override
    public void create(){
        System.out.println("create----");
    }
    @Override
    public void retrieve(){
        System.out.println("retrieve----");
    }
    @Override
    public void update(){
        System.out.println("update----");
    }
    @Override
    public void delete(){
        System.out.println("delete-----");
    }
}

2、创建切面类:MyAspect,写增强方法 myBefore ,myAfter;

package com.woo.service.impl;

public class MyAspect {

    public void myBefore(){
        System.out.println("before");
    }

    public void myAfter(){
        System.out.println("after");
    }
}

3、创建代理类:MyFactory

package com.woo.factory;

import com.woo.service.impl.CustomerServiceImpl;
import com.woo.service.impl.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyFactory {

    public static CustomerServiceImpl getCgLibBean(){
        //创建目标类
        final CustomerServiceImpl customerServiceImpl = new CustomerServiceImpl();
        //创建切面类
        final MyAspect myAspect = new MyAspect();
        //生成代理,CGLIB在运行时,生成指定对象的子类,增强
        Enhancer enhancer = new Enhancer();
        //确定需要增强的类
        enhancer.setSuperclass(CustomerServiceImpl.class);
        //添加回调函数;
        enhancer.setCallback(new MethodInterceptor() {
            //intercept相当于JDK代理的invoke方法
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                myAspect.myAfter();
                Object obj = method.invoke(customerServiceImpl,objects);
                myAspect.myBefore();
                return obj;
            }
        });
        //创建代理类
        CustomerServiceImpl customerServiceImplProxy = (CustomerServiceImpl) enhancer.create();
        return customerServiceImplProxy;
    }
}

4、测试:

@Test
    public void test4(){
        //从工厂获取指定的内容,
        CustomerServiceImpl customerServiceImpl = MyFactory.getCgLibBean();
        //执行方法
        customerServiceImpl.create();
        customerServiceImpl.retrieve();
        customerServiceImpl.update();
        customerServiceImpl.delete();
    }

5、输出:

Spring AOP 声明式创建 AOP代理

1、创建业务类接口 CustomerService 以及业务类实现类 CustomerServiceImpl;

package com.woo.service;

public interface CustomerService {
    //crud
    void create();

    void retrieve();

    void update();

    void delete();
}
package com.woo.service.impl;

import com.woo.service.CustomerService;

public class CustomerServiceImpl implements CustomerService {

    @Override
    public void create(){
        System.out.println("create----");
    }
    @Override
    public void retrieve(){
        System.out.println("retrieve----");
    }
    @Override
    public void update(){
        System.out.println("update----");
    }
    @Override
    public void delete(){
        System.out.println("delete-----");
    }
}

2、创建切面类:SpringMyAspect,实现接口:MethodInterceptor写增强方法 myBefore ,myAfter;

package com.woo.service.impl;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

//需要实现接口,确定哪个通知,及告诉Spring 应该执行哪个方法;
public class SpringMyAspect implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("方法执行之前---");
        //执行目标方法
        Object obj = methodInvocation.proceed();
        System.out.println("方法执行之后---");
        return obj;
    }
}

3、修改Spring 配置文件:

<?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"
       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">

    <!--
    xmlns 即 xml namespace xml 使用的命名空间
    xmlns:xsi 即 xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档 xml 遵守的规范 官方指定
    -->

    <!--目标类-->
    <bean id = "customerService" class="com.woo.service.impl.CustomerServiceImpl"/>
    <!--通知advice-->
    <bean id = "springMyAspect" class="com.woo.service.impl.SpringMyAspect"/>
    <!--生成代理对象-->
    <bean id = "customerServiceProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">
        <!--代理实现接口-->
        <property name = "proxyInterfaces" value = "com.woo.service.CustomerService" />
        <!--代理目标对象-->
        <property name = "target" ref = "customerService"/>
        <!--用通知增强目标-->
        <property name = "interceptorNames" value="springMyAspect"/>
        <!--如何生成代理,true-使用CGLIB,false-使用JDK-->
        <property name = "proxyTargetClass" value = "true"/>
    </bean>

</beans>

4、测试:

   @Test
    public void test5(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        CustomerService customerService = (CustomerService) context.getBean("customerServiceProxy");
        customerService.create();
        customerService.retrieve();
        customerService.update();
        customerService.delete();
    }

5、输出:

AspectJ 基于XML声明式创建AOP代理:

1、加入maven依赖

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.8.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjtools</artifactId>
  <version>1.8.9</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.7.4</version>
</dependency>

2、创建业务类接口CustomerService和业务类CustomerServiceImpl

package com.woo.service;

public interface CustomerService {
    //crud
    void create();

    void retrieve();

    void update();

    void delete();
}
package com.woo.service.impl;

import com.woo.service.CustomerService;

public class CustomerServiceImpl implements CustomerService {

    @Override
    public void create(){
        System.out.println("create----");
    }
    @Override
    public void retrieve(){
        System.out.println("retrieve----");
    }
    @Override
    public void update(){
        System.out.println("update----");
    }
    @Override
    public void delete(){
        System.out.println("delete-----");
    }
}

3、创建切面类 MyAspectJ

package com.woo.service.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspectJ {
    //前置通知,joinPoint 参数可以获得目标对象的类名、目标方法名和目标方法参数等
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知---");
        System.out.println(joinPoint.getTarget() + "方法名称:" + joinPoint.getSignature().getName());
    }
    //后置通知
    public void myAfter(JoinPoint joinPoint){
        System.out.println("后置通知---");
        System.out.println(joinPoint.getTarget() + "方法名称:" + joinPoint.getSignature().getName());
    }
    //环绕通知,必须有入参proceedingJoinPoint,有返回obj,抛出异常Throwable
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知开始---");
        Object obj = proceedingJoinPoint.proceed();//执行当前目标方法
        System.out.println("环绕通知结束---");
        return obj;
    }
    //异常通知,throwable用于输出异常信息
    public void myThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("异常通知,出错了:---" + throwable.getMessage());
    }
    //最终通知
    public void myFinally(){
        System.out.println("最终通知---");
    }
}

4、配置Spring.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">

    <!--目标类-->
    <bean id = "customerService" class="com.woo.service.impl.CustomerServiceImpl"/>
    <!--切面类-->
    <bean id = "myAspectJ" class="com.woo.service.impl.MyAspectJ"/>
    <!--AOP编程-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect ref="myAspectJ">
            <!--配置切入点,通知使用哪些增强方法-->
            <aop:pointcut id = "myPointCut" expression="execution(* com.woo.service.*.*(..))"/>
            <!--前置通知,关联通知advice和切入点pointCut-->
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            <!--后置通知,在方法返回之后执行,就可以获得返回值returning属性-->
            <aop:after-returning method="myAfter" pointcut-ref="myPointCut" />
            <!--环绕通知-->
            <aop:around method="myAround" pointcut-ref="myPointCut" />
            <!--异常通知,throwing用于设置属性名称-->
            <aop:after-throwing method="myThrowing" pointcut-ref="myPointCut" throwing="throwable"/>
            <!--最终通知,无论程序发生什么,都会执行-->
            <aop:after method="myFinally" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>

</beans>

5、测试

 @Test
    public void test6(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        CustomerService customerService = (CustomerService) context.getBean("customerService");
        customerService.create();
    }

6、输出

AspectJ 基于Annotation声明式创建AOP代理:

1、创建业务类接口CustomerService和业务类CustomerServiceImpl 

package com.woo.service;

public interface CustomerService {
    //crud
    void create();

    void retrieve();

    void update();

    void delete();
}
package com.woo.service.impl;

import com.woo.service.CustomerService;
import org.springframework.stereotype.Service;

@Service(value = "customerService")
public class CustomerServiceImpl implements CustomerService {

    @Override
    public void create(){
        System.out.println("create----");
    }
    @Override
    public void retrieve(){
        System.out.println("retrieve----");
    }
    @Override
    public void update(){
        System.out.println("update----");
    }
    @Override
    public void delete(){
        System.out.println("delete-----");
    }
}

2、创建切面类 MyAspectJAnno

package com.woo.service.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspectJAnno {
    /**
     * 用于取代<aop:pointcut id = "myPointCut" expression="execution(* com.woo.service.*.*(..))"/>
     * rule:方法必须是private,空方法,名称自定义,没有入参
     */
    @Pointcut(value = "execution(* com.woo.service.*.*(..))")
    private void myPointCut(){
    }
    //前置通知
    @Before(value = "myPointCut()")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知---");
        System.out.println(joinPoint.getTarget() + "方法名称:" + joinPoint.getSignature().getName());
    }
    //后置通知
    @AfterReturning(value = "myPointCut()")
    public void myAfter(JoinPoint joinPoint){
        System.out.println("后置通知---");
        System.out.println(joinPoint.getTarget() + "方法名称:" + joinPoint.getSignature().getName());
    }
    //环绕通知
    @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知开始---");
        Object obj = proceedingJoinPoint.proceed();//执行当前目标方法
        System.out.println("环绕通知结束---");
        return obj;
    }
    //异常通知
    @AfterThrowing(value = "myPointCut()",throwing = "throwable")
    public void myThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("异常通知,出错了:---" + throwable.getMessage());
    }
    //最终通知
    @After(value = "myPointCut()")
    public void myFinally(){
        System.out.println("最终通知---");
    }
}

3、配置Spring.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">

    <!--扫描com.woo包下的所有注解-->
    <context:component-scan base-package="com.woo"/>
    <!--使用切面,开启自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

4、测试

@Test
    public void test6(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        CustomerService customerService = (CustomerService) context.getBean("customerService");
        customerService.create();
    }

5、输出

注:AspectJ 的两种实现 AOP 的方式 测试出的 通知顺序略有不同。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值