动态代理
特点 : 无侵入式的给代码增加额外的功能 ;
代理里面就是对象要被代理的方法 ;
通过接口保证,后面的对象和代理需要实现同一个接口 , 接口中就是被代理的所有方法 ;
如何为java对象创建一个代理 :
-
java.lang.reflect.Proxy类 : 提供了为对象产生代理对象的方法 :
public static Object newProxyInstance(ClassLoader,Class<?>[] interfaces,InvocationHandler h) 参数一 : 用于指定用那个类加载器,去加载生成的代理类 参数二 : 指定接口,这些接口用于指定生成的代理长什么,也就是什么方法 参数三 : 用来指定生成的代理对象要干什么事情
实例代码 :
首先是一个需要代理的对象 : BigStar :
package com.it.yss;
public class Bigstar implements Star{private String name ;
public Bigstar() {}
public Bigstar(String name) {this.name = name;}
// 唱歌 , 跳舞@Overridepublic String sing(String name){System.out.println(this.name+"正在唱 : " + name);return "谢谢" ;}
@Overridepublic void dance(){System.out.println(this.name+"正在跳舞。") ;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
定义接口Star,指定需要被代理的方法 :
package com.it.yss;
public interface Star {// 我们可以把所有想被代理的方法定义在接口当中
// 唱歌public abstract String sing(String name) ;
// 跳舞public abstract void dance() ;
}
创建代理ProxyUtil :
package com.it.yss;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**** 类的作用 :* 创建一个代理**/
public class ProxyUtil {/*** 方法的作用 :* 给一个明星的对象 ,创建一个代理** 形参 :* 被代理的明星对象** 返回值 :* 给明星创建的代理** 需求 :* 外面的人想要大明星唱一首歌* 1 . 获取代理的对象* 代理对象 = ProxyUtil.createProxy(大明星的对象)* 2 . 再 调用代理的唱歌对象* 代理对象.唱歌的方法("歌曲的名称") ;*/public static Star createProxy(Bigstar bigstar){/*java.lang.reflect.Proxy类 : 提供了为对象产生代理对象的方法
public static Object newProxyInstance(ClassLoader,Class<?>[] interfaces,InvocationHandler h)参数一 : 用于指定用那个类加载器,去加载生成的代理类参数二 : 指定接口,这些接口用于指定生成的代理长什么,也就是什么方法参数三 : 用来指定生成的代理对象要干什么事情
*/Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//参数一 : 用于指定用那个类加载器,去加载生成的代理类new Class[]{Star.class},//指定接口,这些接口用于指定生成的代理长什么,也就是什么方法// 参数三 : 用来指定生成的代理对象要干什么事情new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*** 参数一 : 代理的对象* 参数二 : 要运行的方法 sing* 参数三 : 调用sing方法时 , 传递的实参*/if("sing".equals(method.getName())){System.out.println("准备话筒 , 收钱");}else if("dance".equals(method.getName())){System.out.println("准备场地 , 收钱");}// 去找大明星唱歌或者跳舞// 代码的表现形式 : 调用大明星里面唱歌或者跳舞的方法return method.invoke(bigstar,args);}}) ;
return star ;
}
}
测试 :
package com.it.yss;
public class test {public static void main(String[] args) {
// * 需求 :
// * 外面的人想要大明星唱一首歌
// * 1 . 获取代理的对象
// * 代理对象 = ProxyUtil.createProxy(大明星的对象)
// * 2 . 再 调用代理的唱歌对象
// * 代理对象.唱歌的方法("歌曲的名称") ;// 1 . 获取代理的对象Bigstar bigstar = new Bigstar("鸡哥") ;Star proxy = ProxyUtil.createProxy(bigstar) ;
// 2 . 调用唱歌的方法String result = proxy.sing("只因你太美") ;System.out.println(result);
// 3 . 调用跳舞的方法proxy.dance();}
}
调用步骤 :
反射
概念 :
反射 :
反射允许对封装类的成员变量,成员方法和构造方法的信息进行编程访问 ;
一个类包括 :
-
字段(成员变量)
-
构造方法
-
成员方法
而反射就可以将这些获取出来 , 例如idea中的类方法或构造函数参数提示就是依靠反射实现的 :
获取class对象的三种方式 :
-
Class.forName("全类名")
-
类名.class
-
对象.getClass() ;
代码实例 :
package com.it.yss;
public class MyReflectDemo1 {public static void main(String[] args) throws ClassNotFoundException {/*** 获取class对象的三种方式 :* 1. Class.forName("全类名")* 2. 类名.class* 3. 对象.getClass() ;*/// 1. 第一种方式// 全类名 : 包名 + 类名 com.it.yss.Student// 最为常用的Class Clazz = Class.forName("com.it.yss.Student");// 打印 :System.out.println(Clazz);
// 2 .第二种方式// 一般更多的是当作参数进行传递Class Clazz2 = Student.class ;System.out.println(Clazz2==Clazz);
// 3 . 第三种方式// 当有了这个类的对象的时候 , 才能使用Student stu = new Student();Class Clazz3 = stu.getClass();System.out.println(Clazz3==Clazz2);}
}
可以看到全是相等的 ,输出结果 :
class com.it.yss.Student
true
true
在java中 , 万事皆可看作对象 :
获取构造方法 :
实例 :
Student类 :
package com.it.myreflect2;
public class Student {private String name ;private int age;
public Student() {}
public Student(String name){this.name = name;}
public Student(int age){this.age = age;}
public Student(String name, int age) {this.name = name;this.age = age ;}
public String getName(){return name;}
public void setName(String name){this.name = name;}
public int getAge(){return age;}
public void setAge(int age){this.age = age;}
@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
1 . 获取字节码文件对象 :
Class clazz = Class.forName("com.it.myreflect2.Student");
2 . 获取构造方法
// 2 . 2 获取所有构造方法Constructor[] cons2 = clazz.getDeclaredConstructors();for (Constructor c : cons2) {System.out.println(c);}
System.out.println("------------------------");
// 2 . 3 获取空参构造方法Constructor con1 = clazz.getDeclaredConstructor() ;System.out.println(con1);
System.out.println("------------------------");
// 2 . 4 获取对应的构造方法(传入对应参数的字节码文件)Constructor con2 = clazz.getDeclaredConstructor(String.class);System.out.println(con2);Constructor con3 = clazz.getDeclaredConstructor(int.class);System.out.println(con3);Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class);System.out.println(con4);
System.out.println("------------------------");
输出结果 :
public com.it.myreflect2.Student()
public com.it.myreflect2.Student(java.lang.String)
------------------------
public com.it.myreflect2.Student()
public com.it.myreflect2.Student(java.lang.String)
protected com.it.myreflect2.Student(int)
private com.it.myreflect2.Student(java.lang.String,int)
------------------------
public com.it.myreflect2.Student()
------------------------
public com.it.myreflect2.Student(java.lang.String)
protected com.it.myreflect2.Student(int)
private com.it.myreflect2.Student(java.lang.String,int)
------------------------
3 . 获取构造方法修饰权限符
// 3 获取方法修饰权限符
int modifiers = con4.getModifiers();
System.out.println(modifiers);
System.out.println("------------------------");
这里输出结果是2 , 看api文档可以发现2对应的是private ;
4 . 获取构造方法参数
用con.getParameters()来获得对应的参数列表 :
Parameter[] parameters = con4.getParameters();
for (Parameter p : parameters) {System.out.println(p);
}
输出结果 :
java.lang.String arg0
int arg1
5 . 用反射创建对象
// 暴力反射 : 临时取消权限校验(原本是私有构造方法)
con4.setAccessible(true);
// 创建对象
Student stu = (Student) con4.newInstance("张三",23);
System.out.println(stu);
输出结果 :
Student{name='张三', age=23}
利用反射获取成员变量
Student类 :
package com.it.myreflect3;
public class Student {private String name ;private int age;public String gender ;public Student() {}public Student(int age, String gender, String name) {this.age = age;this.gender = gender;this.name = name;}public String getName(){return name;}public void setName(String name){this.name = name;}public int getAge(){return age;}public void setAge(int age){this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';}
}
1 . 获取成员变量 :
// 2 . 获取成员变量Field[] fields1 = clazz.getFields() ;//获取公共Field[] fields2 = clazz.getDeclaredFields() ;// 获取所有for(Field f : fields1){System.out.println(f);}System.out.println("--------------");for(Field f : fields2){System.out.println(f);}System.out.println("--------------");// 获取单个成员变量Field gender = clazz.getDeclaredField("gender");System.out.println(gender);
输出结果 :
public java.lang.String com.it.myreflect3.Student.gender
--------------
private java.lang.String com.it.myreflect3.Student.name
private int com.it.myreflect3.Student.age
public java.lang.String com.it.myreflect3.Student.gender
--------------
public java.lang.String com.it.myreflect3.Student.gender
2 . 获取权限修饰符
int modifiers = gender.getModifiers();
System.out.println(modifiers);
输出结果 :
1
1代表public
3 . 获取成员变量,类型
String ys = gender.getName() ;
System.out.println(ys);
Class<?> type = gender.getType();
System.out.println(type);
输出结果 :
gender
class java.lang.String
4 . 获取成员变量记录的值
Student s = new Student(23,"男","张三");
Object value = gender.get(s) ;
System.out.println(value);
输出结果 :
男
5 . 修改对象里面记录的值
gender.set(s,"女");
System.out.println(s);
输出结果 :
Student{name='张三', age=23, gender='女'}
获取成员方法
Student类 :
package com.it.myreflect4;
import java.io.IOException;
public class Student {private String name ;private int age;
public Student() {}
private Student(String name, int age) {this.name = name;this.age = age ;}
public void sleep(){System.out.println("睡觉");}
private String eat(String food) throws IOException {System.out.println("在吃"+food);return "奥里给" ;}
public String getName(){return name;}
public void setName(String name){this.name = name;}
public int getAge(){return age;}
public void setAge(int age){this.age = age;}
@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
注 : 多加了eat()和sleep();
完整代码 :
package com.it.myreflect4;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class test {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {// 1 . 获取字节码文件对象Class clazz = Class.forName("com.it.myreflect4.Student");
// 2 . 获取所有的方法对象(包含父类中所有的公共方法)Method[] methods= clazz.getMethods();for(Method method:methods){System.out.println(method);}
//获取所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)Method[] methods1= clazz.getDeclaredMethods();for(Method method:methods1){System.out.println(method);}
// 获取指定的单一方法Method m = clazz.getDeclaredMethod("eat", String.class) ;System.out.println(m);
// 获取方法的修饰符int modify = m.getModifiers();System.out.println(modify);
// 获取方法的名字String name = m.getName() ;System.out.println(name);
// 获取方法的形参Parameter[] ps = m.getParameters();for(Parameter p : ps){System.out.println(p);}
// 获取方法抛出的异常 :Class[] exceptionTypes = m.getExceptionTypes();for(Class exceptionType : exceptionTypes){System.out.println(exceptionType);}
// 方法运行/*Method类中用于创建对象的方法Object invoke(Object obj,Object... args): 运行方法参数一 : 用obj对象调用该方法参数二 : 调用方法的传递的参数(如果没有就不写)返回值: 方法的返回值(如果没有就不写)*/Student s = new Student() ;m.setAccessible(true);String ts = (String) m.invoke(s, "汉堡包");System.out.println(ts);
}
}
输出结果 :
public java.lang.String com.it.myreflect4.Student.getName()
public java.lang.String com.it.myreflect4.Student.toString()
public void com.it.myreflect4.Student.sleep()
public void com.it.myreflect4.Student.setName(java.lang.String)
public int com.it.myreflect4.Student.getAge()
public void com.it.myreflect4.Student.setAge(int)
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
public java.lang.String com.it.myreflect4.Student.getName()
public java.lang.String com.it.myreflect4.Student.toString()
public void com.it.myreflect4.Student.sleep()
public void com.it.myreflect4.Student.setName(java.lang.String)
private java.lang.String com.it.myreflect4.Student.eat(java.lang.String) throws java.io.IOException
public int com.it.myreflect4.Student.getAge()
public void com.it.myreflect4.Student.setAge(int)
private java.lang.String com.it.myreflect4.Student.eat(java.lang.String) throws java.io.IOException
2
eat
java.lang.String arg0
class java.io.IOException
在吃汉堡包
奥里给
反射的作用
-
获取一个类里面的所有的信息 , 获取到之后,再执行其它的业务逻辑
-
结合配置文件,动态的创建对象并调用方法