【Java基础】java中的反射机制与动态代理
一、java中的反射机制
java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法。这种动态获取类的信息及动态调用类中方法的功能称为java的反射机制。
获取一个类的Class对象是应用反射机制的前提,获取Class对象的方式有如下三种:
instance.getClass(),这个是Object类里面的方法
Type.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类
- Class.forName("类的全名"),Class类提供了这样一个方法,让我们通过类名来获取到对象类
1. 通过反射机制操作某个类的属性
package net.xsoftlab.baike;
import java.lang.reflect.Field;
public class TestReflect {
private String proprety = null;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
Object obj = clazz.newInstance();
// 可以直接对 private 的属性赋值
Field field = clazz.getDeclaredField("proprety");
field.setAccessible(true);
field.set(obj, "Java反射机制");
System.out.println(field.get(obj));
}
}
2. 通过反射机制调用某个类的方法
package net.xsoftlab.baike;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
// 调用TestReflect类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// Java 反射机制 - 调用某个类的方法1.
// 调用TestReflect的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
// Java 反射机制 - 调用某个类的方法2.
// age -> 20. name -> 张三
}
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法1.");
}
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法2.");
System.out.println("age -> " + age + ". name -> " + name);
}
}
二、动态代理
2.1 动态代理AOP
java代理模式的定义:用一个对象来控制对另一个对象的访问,称控制对象为代理对象,被控制对象为被代理对象或真实对象。通过调用代理对象的方法来间接访问被代理对象中的同名方法,要保证二者具有同名方法通常将这些同名方法抽象成接口,由二者共同实现。
动态代理和静态代理的区别:静态代理必须要为每个真实类定义一个代理类,而动态代理中无需定义代理类,由java反射包中的Proxy类动态的创建代理对象或代理类。
在java的动态代理机制中,有一个类和接口至关重要,Proxy类用于动态创建代理类或代理对象,调度处理器接口InvocationHandler。每个动态代理对象必须与实现了InvocationHandler接口的实例关联,代理对象每个方法的内部都调用了此关联实例的invoke 方法,而invoke 方法的内部又利用反射机制调用真是对象的方法,从而实现了由代理对象访问真实对象的目的。
下面是实现动态代理的经典案例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; //定义真实类和代理类共同的接口
interface Subject {
public void rent(); public void hello(String str);
} //定义真实类(被代理类
class RealSubject implements Subject {
@Override
public void rent() {
System.out.println("I want to rent my house");
} @Override
public void hello(String str) {
System.out.println("hello: " + str);
}
} //定义继承了InvocationHandler接口的调度处理器
public class MyInvocationHandler implements InvocationHandler {
//要代理的真实对象
private Object realObj; // 构造方法给要代理的真实对象赋值
public MyInvocationHandler(Object realObj) {
this.realObj = realObj;
} /**
* 执行动态代理对象的所有方法都会被替换为执行如下的invoke方法
* 其中:
* autoProxy:动态代理对象
* method:代表正在执行的方法
* args:由动态代理对象调用方法时传入的实参
*/
@Override
public Object invoke(Object autoProxy, Method method, Object[] args) throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("before rent invoke");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
System.out.println("Method:" + method);
method.invoke(realObj, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent invoke");
return null;
} } class Client {
public static void main(String[] args) {
//要代理的真实对象
Subject realObj = new RealSubject();
//要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler MyHandler = new MyInvocationHandler(realObj);
/*通过Proxy类的newProxyInstance方法动态创建代理对象
*public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
* 它的三个参数
* 第一个参数 指定动态代理类的类加载器
* 第二个参数 指定动态代理类需实现的接口集合
* 第三个参数 指定与该动态代理对象所关联的调度处理器实例
*/
Subject autoProxy = (Subject) Proxy.newProxyInstance(MyHandler.getClass().getClassLoader(), realObj.getClass().getInterfaces(), MyHandler);
System.out.println(autoProxy.getClass().getName());
autoProxy.rent();
autoProxy.hello("world");
}
}
输出如下:
net.xsoftlab.baike.$Proxy0
before rent invoke
Method:public abstract void net.xsoftlab.baike.Subject.rent()
I want to rent my house
after rent invoke
before rent invoke
Method:public abstract void net.xsoftlab.baike.Subject.hello(java.lang.String)
hello: world
after rent invoke
总结:1.动态代理中无需定义代理类,代理对象是由Proxy类动态产生的。
2.代理对象对方法的访问都将转换成调度处理器对其invoke 方法的访问。
3.调度处理器的invoke 方法内部利用反射机制去调用真是对象的同名方法。
4.像上面这种动态代理在Spring中被称为AOP(Aspect Orient Programming,面向切面编程),AOP代理可替代目标对象,AOP代理包含了目标对象的全部方法。
2.2 AOP的应用
上面介绍了动态代理,接下来说下它的应用。在开发中如果要复用同一功能模块,可以通过复制该功能模块的代码来实现,但在开发中一般不会这样做,通常将该功能模块封装成一个方法,在需要的地方直接调用就可以了。
通过将公共模块封装成方法来调用虽然提高了复用减少了代码的冗余,但却提高了这三个代码段与方法的耦合。最理想的效果是:代码块一,代码块二,代码块三既可以执行蓝色区域的代码部分,又无需以硬编码的方式来直接调用蓝色区域的方法。这时就可以通过动态代理来实现这个功能。
接下来使用Proxy和InvocationHandler来实现当程序调用info()或run()方法时,系统可以“自动”将method1()和method2()两个方法插入info()和run()方法中执行。
首先提供一个Dog接口,在该接口中提供两个方法:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Dog {
//info()方法声明
void info(); //run()方法
void run();
} class GunDog implements Dog {
//实现info方法,仅仅打印一个字符串
@Override
public void info() {
System.out.println("我是一只猎狗");
} //实现run()方法,仅仅打印一个字符串
@Override
public void run() {
System.out.println("迅速奔跑");
}
} class DogUtil {
public static void method1() {
System.out.println("=====模拟第一个通用方法=====");
} public static void method2() {
System.out.println("=====模拟第二个通用方法=====");
}
} class MyInvocationHandler implements InvocationHandler {
private Object target; public void setTarget(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行DogUtil对象中method1方法
DogUtil.method1();
//以target作为主调执行method方法
Object result = method.invoke(target, args);
//执行DogUtil对象中的method2方法
DogUtil.method2();
return result;
}
} class MyProxyFactory {
public static Object getProxy(Object target) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
//设置需要代理的对象
myInvocationHandler.setTarget(target);
//创建并返回动态代理
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInvocationHandler);//使用指定的类加载器,需要实现的接口,自定义Handler
}
} public class TestAOP {
public static void main(String[] args) {
Dog dog = (Dog) MyProxyFactory.getProxy(new GunDog());
dog.info();
dog.run();
}
}
输出如下:
=====模拟第一个通用方法=====
我是一只猎狗
=====模拟第二个通用方法=====
=====模拟第一个通用方法=====
迅速奔跑
=====模拟第二个通用方法=====
下面这张图片对上面的程序流程进行了简单解释:
本篇博文参考了:【java】解析java类加载与反射机制 java的动态代理机制详解
【Java基础】java中的反射机制与动态代理的更多相关文章
- Java中的反射机制和动态代理
一.反射概述 反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法:对于任意一个对象 ...
- Java反射机制以及动态代理
Java反射机制以及动态代理 Java反射机制 含义与功能 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类 ...
- java反射机制与动态代理
在学习HadoopRPC时.用到了函数调用.函数调用都是採用的java的反射机制和动态代理来实现的,所以如今回想下java的反射和动态代理的相关知识. 一.反射 JAVA反射机制定义: JAVA反射机 ...
- Java基础系列 - 泛型和反射机制
package com.test5; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Java泛型和反射机 ...
- java.lang.Class<T> -- 反射机制及动态代理
Interface : Person package java_.lang_.component.bean; public interface Person { String area = " ...
- Java的反射机制和动态代理
介绍Java注解的时候,多次提到了Java的反射API.与javax.lang.model不同的是,通过反射API可以获取程序在运行时刻的内部结构.反射API中提供的动态代理也是非常强大的功能,可以原 ...
- java学习笔记13--反射机制与动态代理
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...
- Spring AOP中的JDK和CGLib动态代理哪个效率更高?
一.背景 今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高? 二.基本概念 首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理, ...
- Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题
Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只 ...
随机推荐
- 在 UIViewController 中手动增加 TableView 出现 Type 'SomeViewController' does not confirm to protocol 'UITableViewDataSource' 问题的解决办法
许多时候我们都有在普通的继承自 UIViewController 的控制器中使用 TableView 的需求,这时候就需要当前控制器类继承 UITableViewDelegate 和 UITableV ...
- 基于 Laravel 开发 ThinkSNS+ 中前端的抉择(webpack/Vue)踩坑日记
在上一篇文章< ThinkSNS+基于Laravel master分支,从1到 0,再到0.1>,简单的介绍了 ThinkSNS+ ,这里分享在开发过程中,前端选择的心理活动. Larav ...
- 【UVA - 10815】Andy's First Dictionary (set)
Andy's First Dictionary Description 不提英文了 直接上中文大意吧 XY学长刚刚立下了再不过CET就直播xx的flag,为了不真的开启直播模式,XY学长决定好好学习英 ...
- 【Luogu P1502】 窗口的星星
→传送窗口 (复制一下题面好了~) 题目背景 小卡买到了一套新房子,他十分的高兴,在房间里转来转去. 题目描述 晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户,天真的小 ...
- Vuex目录结构推荐
目录结构如下: - src - store // 在src目录下 新建一个store文件夹 - mutations.js // mutations - mutaions_types.js // mut ...
- Cstring的使用
https://msdn.microsoft.com/zh-cn/aa315043 1.字符串提取函数,CString::Left.CString::Mid .CString::Right CStri ...
- Hive_Hive体系结构
元数据: HQL的执行过程 ORACEL 执行计划,Hive 类似. 无索引时,生成全表扫描执行计划,执行全表扫描. 创建索引后,重新生成SQL语句执行计划,基于索引扫描,提高查询效率.
- 防止a标签跳转的几种方法
第一种方法 在a标签的href中添加属性值 <a href="javascript:void(0)"></a> 第二种方法 给a标签添加点击事件,函数的返回 ...
- 接口测试03 - Python HTTP库requests
概述: 整理一些requests的相关知识,及如何使用requests进行接口测试. requests号称:是唯一的一个非转基因的Python HTTP库,人类可以安全享用. 安装: 先看下怎么安装r ...
- python_18(Django基础)
第1章 web框架的本质 1.1 socket 1.2 空格后面是主体内容 1.3 HTTP协议 1.3.1 响应流程 1.4 HTTP请求方法 1.5 HTTP工作原理 1.6 URL 1.7 HT ...