Java反射和代理
反射
什么是反射
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到类对象之后,再通过类对象进行反编译,从而获取对象的各种信息。
获取类的3种方法
- 1、Class.forName("全类名"):将字节吗文件加载进内存,返回Class对象,多用于配指文件,将类名定义在配置文件中,便于利用java的反射机制生成类对象,加载类。
//加载一个用户实体类UserBean
Class c1 = Class.forName("com.test.UserBean");
- 2、类名.class:通过类名的属性class获取,多用于传递参数。
Class c2 = UserBean.class;
- 3、对象.getClass():多用于对象获取字节码的方式。
UserBean user = new UserBean();
Class c3 = user.getClass();
有了类就可以通过反射的方式来创建对象、操作属性和操作方法
通过类创建对象
- 1、使用newInstance()方法。
Object obj = stuClass.newInstance();
Student stu = (Student) obj;
- 2、反射获取构造函数,使用构造函数的方式创建对象。
Constructor<?> constructor = stuClass.getConstructor(int.class, String.class);
Object obj2 = constructor.newInstance(12, "23");
Student stu2 = (Student) obj2;
通过类获取构造器
| 方法 | 用途 | 
|---|---|
| getConstructor(Class<?>... parameterTypes) | 获取与参数类型匹配的public类型的构造方法 | 
| getConstructors() | 获取所有的public类型的构造方法 | 
| getDeclaredConstructor(Class...<?> parameterTypes) | 获取与参数类型匹配的所有构造方法 | 
| getDeclaredConstructors() | 获取所有的构造方法 | 
通过类操作属性
| 方法 | 用途 | 
|---|---|
| getField(String name) | 获取某个public类型的属性 | 
| getFields() | 获取所有的public类型的属性 | 
| getDeclaredField(String name) | 获取某个属性对象 | 
| getDeclaredFields() | 获取所有的属性对象 | 
// 获取类
Class<Student> stuClass = (Class<Student>) Class.forName("data.Student");
// 通过类实例化对象,对象属性都是空的 
final Student student = stuClass.newInstance();
// 获取对象public修饰的属性
final Field score = stuClass.getField("score");
// 给属性赋值
score.set(student, 12);
// 获取对象private修饰的属性并赋值
final Field age = stuClass.getDeclaredField("age");
age.setAccessible(true);
age.set(student, 12);
通过类操作方法
| 方法 | 用途 | 
|---|---|
| getMethod(String name, Class...<?> parameterTypes) | 获取与参数类型匹配的public类型的方法 | 
| getMethods() | 获取所有的public类型的方法(包含继承的方法 | 
| getDeclaredMethod(String name, Class...<?> parameterTypes) | 获取与参数类型匹配的所有方法 | 
| getDeclaredMethods() | 获取所有的方法 | 
获取到函数后,我们可以使用invoke(Object obj, Object... args)来调用对象的函数,并同时给其进行传参。使用getMethods()来调用公有方法:
Class<Student> stuClass = (Class<Student>) Class.forName("data.Student");
final Student student = stuClass.newInstance();
final Method study = stuClass.getMethod("study");
study.invoke(student);
反射的使用
反射最大的作用就在于我们可以不在编译时知道某个对象的类型,而在运行时得到。同时我们只需要得到我们想得到的类的名字即可(如果不在一个包,必须写完整的名字包括包名)。
/**
	成员变量:field对象(因为可能会有多个成员变量,一般用数组存储)
	构造方法:Constructor Constructor[]
	成员方法:Method Method[]
*/
public class Main {
	public static void main(String[] args) throws Exception{
		//返回A的构造方法
		Constructor c = A.class.getConstructor();
		//返回A类的所有为public 声明的构造方法
		Constructor[] cons = A.class.getConstructors();
		//返回A类所有的构造方法,包括private
		Constructor[] cons2 = A.class.getDeclaredConstructors();
		//返回A类的第一个public 方法
		Method m = A.class.getMethod("say");
		//执行
		m.invoke(A.class.newInstance(), null);
		//返回A类所有的public 方法
		Method[] ms = A.class.getMethods();
		//返回A类所有的方法,包括private
		Method[] allMs = A.class.getDeclaredMethods();
		//返回A类的public字段
		Field field = A.class.getField("i");
		System.out.println(field.get(A.class.newInstance()));
		//返回A类的static 字段
		System.out.println(field.get(null));
	}
}
 
class A{
	public int i = 1;
	public static int b = 2;
	public A(){
		System.out.println("无参构造");
	}
	private A(String s){
		System.out.println("有参构造"+s);
	}
	
	public void say(){
		System.out.println("say");
	}
}
代理
静态代理
静态代理需要先定义接口,被代理对象与代理对象一起实现相同的接口,代理类持有目标类的引用,然后通过调用相同的方法来调用目标对象的方法
举个栗子:
接口类 CarInterfaces.class,定义一组接口
interface CarInterfaces {
    void run();
}
目标类 Car.class
public class Car implements CarInterfaces {
    @Override
    public void run() {
        System.out.println("Car run()");
    }
}
代理类 CarSystemProxy.class
public class CarSystemProxy implements CarInterfaces {
    Car car;
    @Override
    public void run() {
        System.out.println("before car run");
        if (car == null) {
            car = new Car();
        }
        car.run();
        System.out.println("after car run");
    }
}
当目标类接口增多后,代理类要代理新增的接口,如果按照静态代理的模式,代理类中要同步新增接口,这时候就显得比较麻烦
动态代理
动态代理与静态代理的区别主要在:
- 静态代理在编译时就已经实现
- 动态代理是在运行时动态生成的,在运行时动态生成类字节码,并加载到JVM中
两种常见的动态代理方式:JDK原生动态代理和CGLIB动态代理
JDK动态代理
JDK动态代理:Java自动生成代理类class对象,保存在内存中,通过反射获取代理类的构造方法,进而创建代理类的实例对象
public class RenterInvocationHandler<T> implements InvocationHandler{
	//被代理类的对象
	private T target;
	
	public RenterInvocationHandler(T target){
		this.target = target;
	}
	/**
        * proxy:代表动态代理对象
        * method:代表正在执行的方法
        * args:代表调用目标方法时传入的实参
        */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//代理过程中插入其他操作
		System.out.println("租客和中介交流");
		Object result = method.invoke(target, args);
		return result;
	}
}
例:
1、业务接口和实现类如下
public interface UserService {
    void login();
}
public class UserServiceImpl implements UserService {
    @Override
    public void login() {
        System.out.println("login success!");
    }
}
2、调用处理器如下
public class UserInvocationHandler implements InvocationHandler {
    // 目标对象
    private Object tarket;
    public UserInvocationHandler() {
    }
    public UserInvocationHandler(Object tarket) {
        this.tarket = tarket;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 调用目标对象的方法
        method.invoke(tarket, null);
        // 增强功能
        System.out.println("login time:" + new Date());
        return null;
    }
}
3、测试
public static void main(String[] args) {
      // 创建目标对象
      UserServiceImpl userService = new UserServiceImpl();
      // 创建调用处理器
      UserInvocationHandler handler = new UserInvocationHandler(userService);
      // 创建代理对象
      UserService proxy = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),
              UserServiceImpl.class.getInterfaces(),
              handler);
      proxy.login();
  }
CGLIB动态代理
CGLIB动态代理:也叫子类代理,通过在内存中构建一个子类,在子类用方法拦截的方式拦截所有父类方法的调用,然后加入自己的操作。因为使用的是继承,不能代理final类
public class ProxyFactory<T> implements MethodInterceptor {
	private T target;
	public ProxyFactory(T target) {
		this.target = target;
	}
	// 创建代理对象
	public Object getProxyInstance() {
		// 1.cglib工具类
		Enhancer en = new Enhancer();
		// 2.设置父类
		en.setSuperclass(this.target.getClass());
		// 3.设置回调函数
		en.setCallback(this);
		return en.create();
	}
        //拦截方法
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		System.out.println("开始事务...");
		// 执行目标对象的方法
		Object result = method.invoke(target, args);
		System.out.println("提交事务...");
		return result;
	}
}
 
                    
                     
                    
                 
                    
                 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号