栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring:AOP原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring:AOP原理

目录

动态代理

基于接口的动态代理

基于子类的动态代理

Spring AOP

基于xml实现

切点表达式

基于注解实现


动态代理

特点:字节码随用随创建,随用随加载

作用:不修改源码的基础上对方法增强

分类

  • 基于接口的动态代理
  • 基于子类的动态代理

基于接口的动态代理

涉及的类:Proxy,提供商是JDK官方

要求:被代理类最少实现一个接口、

创建代理对象: 使用Proxy类中的newProxyInstance方法

newProxyInstance方法的参数

  • 第一个参数:目标对象的额类加载器, 它是用于加载代理对象字节码的。
  • 第二个参数:目标对象相同的接口字节码对象数组, 它是用于让代理对象和被代理对象有相同方法
  • 第三个参数:用于提供增强的代码

InvocationHandler对象中invoke方法的参数

  • 第一个参数:代理对象的引用
  • 第二个参数:当前执行方法
  • 第三个参数:当前执行方法的所需参数

示例代码

//接口
public interface Idomain {
    void t1();
    void t2(int num);
}
//接口实现类
public class dmain implements Idomain {
    @Override
    public void t1() {
        System.out.println("t1方法已被执行");
    }
    @Override
    public void t2(int num) {
        System.out.println("输出结果为num:"+num);

    }
}
//使用代理对象
public void t_1(){
        final dmain dmain = new dmain();//目标对象
        Idomain instance = (Idomain) Proxy.newProxyInstance(dmain.getClass().getClassLoader(), dmain.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object o = null;
                
                if ("t2".equals(method.getName())) {
                    System.out.println("前置代码。。。。");
                    int num = (int) args[0];
                    o = method.invoke(dmain, num * 2);//对dmain对象的这个方法 传入num*2这个参数
                    System.out.println("后置代码。。。");

                }else{
                    System.out.println("前置代码。。。。");
                    o=method.invoke(dmain);
                    System.out.println("后置代码。。。");
                }
                return o;
            }
        });
        instance.t2(4);
        instance.t1();
    }

控制台输出结果

基于子类的动态代理

涉及的类:Enhancer   提供者:第三方cglib库

要求:被代理类不能是最终类

创建代理对象: 使用Enhancer类中的create方法

Enhancer类中的create方法的参数

  • 第一个参数:它是用于指定被代理对象的字节码
  • 第二个参数:用于提供增强的代码

MethodInterceptor对象中intercept方法的参数

  • 第一个参数:代理对象的引用
  • 第二个参数:当前执行方法
  • 第三个参数:当前执行方法的所需参数
  • 第四个参数:当前执行方法的代理对象

需要导入spring核心的坐标:spring-context

//目标类
public class dmain1 {
    public void t1() {
        System.out.println("t1方法已被执行");
    }
    public void t2(int num) {
        System.out.println("输出结果为num:"+num);
        int i=1/0;//制造异常

    }
}
//动态代理
public void t2(){
        final dmain1 dmain1 = new dmain1();//目标对象
         dmain1 o = (dome5.dmain1) Enhancer.create(dmain1.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object o = null;
                if ("t2".equals(method.getName())) {
                    try {
                        System.out.println("前置增强。。。。");
                        int num = (int) args[0];
                        o = method.invoke(dmain1, num * 2);//对dmain对象的这个方法 传入num*2这个参数
                        System.out.println("后置增强。。。");
                    } catch (Exception e) {
                        System.out.println("异常增强代码");
                    } finally {
                        System.out.println("最终增强代码");
                    }

                }
                return o;
            }
        });
         o.t2(3);
    }

控制台输出

Spring AOP

AOP:面向切面编程

作用:在程序运行期间,不修改源码对已有方法进行增强

优点

  • 减少重复代码
  • 提高开发效率
  • 维护方便

实现方式:动态代理技术

Spring的aop就是使用配置的方式实现动态代理

AOP相关术语:

目标对象:需要增强的对象

代理对象:被AOP织入增强后,产生的代理对象

连接点:所有可以拦截的方法

切入点:选择连接点进行拦截

通知/增强:增强代码

切面=切入点+通知

基于xml实现
标签名含义
aop:config进行AOP配置
aop:aspect

声明切面

ref="切面对象"

aop:pointcut

抽取切点表达式  

id=“” 切点表达式的id

expression="切点表达式"

aop:before

前置通知

method="切面类的方法 "

pointcut-ref="切点表达式的id"

pointcut="切点表达式'

aop:after-returning后置通知
aop:after

最终通知

aop:after-throwing异常通知
aop:around环绕通知

环绕通知:

它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。

示例代码

//目标对象类
public class dmain1 {
    public void t1() {
        System.out.println("t1方法已被执行");
        int i=1/0;
    }

}
//切面类(增强类)
public class TranManner {
    public void begin(){
        System.out.println("前置增强");
    }
    public void after(){
        System.out.println("后置增强");
    }
    public void error(){
        System.out.println("异常通知");
    }
    public void after1(){
        System.out.println("最终增强");
    }
//环绕方法
public Object around(ProceedingJoinPoint joinPoint)  {
        Object o=null;
        try {
            System.out.println("前置增强");
            o = joinPoint.proceed();
            System.out.println("后置增强");
        } catch (Throwable throwable) {
            System.out.println("异常通知");
            throwable.printStackTrace();
        }finally {
            System.out.println("最终通知");
        }
        return o;
    }
}



    

    

    

        

            
            
            
            
            
            
        
    



切点表达式
  • 关键字:execution(表达式)
  • 表达式:
    • 访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)
    • 标准的表达式写法:
      • public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
    • 访问修饰符可以省略
    • 参数列表:
    • 可以直接写数据类型:
      • 基本类型直接写名称           int
      • 引用类型写包名.类名的方式   java.lang.String
      • 可以使用通配符表示任意类型,但是必须有参数
      • 可以使用..表示有无参数均可,有参数可以是任意类型
  • 全通配写法:* *..*.*(..)
  • 实际开发中切入点表达式的通常写法  com.itheima.service.impl.*.*(..)

基于注解实现
注解名含义
@Aspect声明切面类
@Before把当前方法看成前置通知
@AfterReturning把当前方法看成后置通知
@AfterThrowing把当前方法看成异常通知
@After把当前方法看成最终通知
@Around把当前通知看成环绕通知
@Pointcut指定切入表达式

示例代码:

//目标对象
@Component("dmain")
public class dmain1 {
    public void t1() {
        System.out.println("t1方法已被执行");
        int i=1/0;
    }

}
//增强类
@Component
@Aspect
public class TranManner {
    @Pointcut("execution(* dome7.dmain1.t1()) ")
    private void pointcut(){}
    @Before("pointcut()")
    public void begin(){
        System.out.println("前置增强");
    }
    @AfterReturning("pointcut()")
    public void after(){
        System.out.println("后置增强");
    }
    @AfterThrowing("pointcut()")
    public void error(){
        System.out.println("异常通知");
    }
    @After("pointcut()")
    public void after1(){
        System.out.println("最终增强");
    }

    public Object around(ProceedingJoinPoint joinPoint)  {
        Object o=null;
        try {
            System.out.println("前置增强");
            o = joinPoint.proceed();
            System.out.println("后置增强");
        } catch (Throwable throwable) {
            System.out.println("异常通知");
            throwable.printStackTrace();
        }finally {
            System.out.println("最终通知");
        }
        return o;
    }
}



    

    



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/358166.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号