前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring框架(七)Java JDK 动态代理(AOP)使用及实现原理分析

Spring框架(七)Java JDK 动态代理(AOP)使用及实现原理分析

作者头像
一写代码就开心
发布2021-07-08 15:06:07
4190
发布2021-07-08 15:06:07
举报
文章被收录于专栏:java和python

目录

回顾Java反射知识

因为动态代理需要用到,所以我们要先学习Java的反射知识。

Java反射中有Method类 Method类,表示方法类中的方法,通过Method可以执行某个类中的某个方法

回顾反射知识咋用

1 先创建一个接口

代码语言:javascript
复制
package com.test;

public interface HelloService {
    // 根据name打招呼
    public void sayHello(String name);
}

2 创建一个类实现这个接口

代码语言:javascript
复制
package com.test;
// HelloService接口的实现类
public class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String name) {
        System.out.println("您好"+name);
    }
}

3 测试,执行HelloServiceImpl这个类里面的方法

代码语言:javascript
复制
package com.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// 测试
public class TestHelloService {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {


// 正常的通过对象调用sayHello方法
创建这个类的对象后执行这个方法,是最普遍的方法
        HelloService helloService = new HelloServiceImpl();
        System.out.println("通过对象调用sayHello方法");
        helloService.sayHello("张三");




通过反射,咋执行这个方法
// 通过反射机制执行sayHello方法,核心Method(类中的方法)
        // 创建需要调用sayHello的对象
        HelloService Service = new HelloServiceImpl();
        // 获取sayHello名称对应的Method类对象
        // method代表的是sayHello这个方法
        /*
            参数:
            1.需要执行的方法名
            2.参数的类型
         */
        Method method = HelloService.class.getMethod("sayHello", String.class);
        
        // 通过Method可以执行sayHello方法的调用
        /*
            invoke是Method类中的一个方法,表示执行方法的调用
            参数:
            1.Object:表示对象,就是要执行这个对象的sayHello方法
            2.Object...args:方法执行时的参数值
            返回值:Object,表示返回执行后的返回值,sayHello返回是void
         */
        // 表示执行Service对象的sayHello返回参数是李四
        System.out.println("通过反射调用sayHello方法");
        Object object = method.invoke(Service,"李四");
    }
}

动态代理

什么叫动态代理

不用自己手动的去创建代理类。 我们自己的一个类,可以创建很多的对象,现在想要在这么多对象上,都要创建代理类。意思是每一个对象都需要创建代理类,我们就可以动态的实现jdk动态代理,实际类和代理类一定要实现同一个接口,这个必须记住

jdk的动态代理:

jdk动态代理使用到 反射包java.lang.reflect,里面包含3个类InvocationHandler、Method、Proxy InvocationHandler接口(调用处理器):Invoke()方法,(需要执行的功能,我的理解:原来的方法和扩展的方法

实现步骤

1 写一个接口,这个接口是实际类和代理类都需要实现的。jdk动态代理就是实际类和代理类都要实现同一个接口,重写里面的 方法,这个是必须的

我们先写一个接口

代码语言:javascript
复制
package com.service;
// 目标类实现的方法
public interface UsbSell {
    public float sell(int amount);
}

2 写一个实际类,实现这个接口,重写里面的方法

这个类就是实际类,我们要对这个里面的方法功能实现扩展。

代码语言:javascript
复制
package com.factory;

import com.service.UsbSell;
// 目标类
public class UsbKingFactory implements UsbSell {
    // 目标方法
    @Override
    public float sell(int amount) {
        System.out.println("执行目标类方法sell");
        return 85.0f;
    }
}

3 创建InvocationHandler接口的实现类 这个是必须的,相当于这个类里面就是写功能扩展的方法。相当于aop, 里面不仅有原来的方法,还有功能扩展的方法

代码语言:javascript
复制
package com.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 必须实现InvocationHandler接口,完成代理功能(1.调用目标方法,2.功能增强)
// 负责执行目标类的方法
// 我的理解:只是执行了目标类的方法和代理类的功能增强,返回目标类方法的返回值给InvocationHandler对象
public class MySellHandle implements InvocationHandler {
    private Object target = null;
    // 动态代理:目标对象是活动的,不是固定的,需要传进来
    // 传入是哪个对象,就给哪个对象创建代理
    public MySellHandle(Object target){
        // 给目标对象赋值
        this.target = target;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        Object res = null;
        
         //在代理真实对象前我们可以添加一些自己的操作
        System.out.println("在调用之前,我要干点啥呢?");
 
        System.out.println("Method:" + method);
 
        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        Object returnValue = method.invoke(target , objects);
 
        //在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("在调用之后,我要干点啥呢?");
 
        return returnValue;
    }
}

4 创建测试类,使用Proxy类的静态方法newProxyInstance,创建代理对象

代码语言:javascript
复制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
 
/**
 * 动态代理演示
 */
public class DynamicProxyDemonstration
{
    public static void main(String[] args)
    {
        //代理的真实对象
        Subject realSubject = new RealSubject();
        
        /**
         * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
         * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
         * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
         */
        InvocationHandler handler = new InvocationHandlerImpl(realSubject);
 
        ClassLoader loader = realSubject.getClass().getClassLoader();
        Class[] interfaces = realSubject.getClass().getInterfaces();
        /**
         * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
         */
        Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
 
        System.out.println("动态代理对象的类型:"+subject.getClass().getName());
 
        String hello = subject.SayHello("ttt");
        System.out.println(hello);
//        String goodbye = subject.SayGoodBye();
//        System.out.println(goodbye);
    }
 
}

注意

注意的是在使用jdk动态代理时目标类一个要实现实现功能接口。

动态代理相当于就是实现 功能的扩展

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/07/02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 回顾Java反射知识
    • 回顾反射知识咋用
    • 动态代理
      • 什么叫动态代理
        • jdk的动态代理:
          • 实现步骤
          • 注意
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档