Java反射和动态代理模式

这两天在学习Java基础(苦逼应届生,要补的东西太多了!)
把复习到的点记录一下,以后复习看!觉得有用的同学可以点下收藏哦!

Java反射机制

应用广泛:类的全限定名、方法和参数,完成对象的初始化,反射某些方法

反射构建对象

举一个例子:
有一个类:

public class ReflectServiceImpl {
	public void sayHello(String name) {
		System.err.println("Hello " + name);
	}

}

如果不用new reflectSerciveImpl()来构建,使用反射的方法构建如下:

public ReflectServiceImpl getInstance() {
		ReflectServiceImpl object = null;
		try {
			object = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl")
					.newInstance();
		} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
			ex.printStackTrace();
		}
		return object;
	}

这个代码就是用class.forName(“全限定名”),然后使用newInstance初始化,最后将其返回。
这个时候可能就有小伙伴疑惑了,如果一个类里面有多个有参构造,那你又怎么用反射解决冲突呢?
哈哈很简单,,废话不多说,我们直接上结果
有一个有多个构造方法的类:

public class ReflectServiceImpl2 {
	private String name;

	public ReflectServiceImpl2(String name) {
		this.name = name;
	}

	public void sayHello() {
		System.err.println("hello " + name);
	}
	
	public ReflectServiceImpl2 getInstance() {
	    ReflectServiceImpl2 object = null;
	    try {
	        object = 
	            (ReflectServiceImpl2) 
	            Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl2").
	            getConstructor(String.class).newInstance("张三");
	    } catch (ClassNotFoundException | InstantiationException 
	                | IllegalAccessException | NoSuchMethodException 
	                | SecurityException | IllegalArgumentException 
	                | InvocationTargetException ex) {
	            ex.printStackTrace();
	    }
	    return object;
	}
}

这个类有两个构造方法,一个有参,一个无参
那么我们如何用反射去构造呢?

看上面代码的这部分:

(ReflectServiceImpl2) 
	            Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl2").
	            getConstructor(String.class).newInstance("张三");

对的,使用了一个getConstrutor方法,他的参数可能是多个,这里定义的String.class,意味着有且只有一个参数的构建方法,以此来区别
总的来说,反射的主要是用来程序的解耦

反射方法

public Object reflectMethod() {
		Object returnObj = null;
		ReflectServiceImpl target = new ReflectServiceImpl();
		try {
			//Method method = ReflectServiceImpl.class.getMethod("sayHello", String.class);
			Method method=target.getClass().getMethod("sayHello", String.class)	;//当有具体对象时也可以这样用
			returnObj = method.invoke(target, "张三");
		} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException ex) {
			ex.printStackTrace();
		}
		return returnObj;
	}

invoke后的target确定用哪个对象的调用方法,张三是参数。相当于target.sayHello(“张三”)。

动态代理模式

先看图:

客户是通过商务去访问软件工程师的,商务可以进行谈判,比如项目启动前的价格,交付时间等。若谈判失败也也不需要软件工程师去处理。
因此,代理的作用为:在真实访问对象之前或者之后加入对应的逻辑,或者根据其他规则控制是否使用真实对象,这个例子中就是商务控制了客户对软件工程师的访问,简单来说就是软件工程师的业务更加存粹,解耦!

JAVA实现动态代理的对象有很多,目前主流的就两个

JDK动态代理

两步走完:
1、代理对象和真实对象建立代理关系
2、实现代理类的代理逻辑方法
先看传统的接口和接口实现类:

接口:

public interface HelloWorld {
	public void sayHelloWorld();
}

实现类:

public class HelloWorldImpl implements HelloWorld {

	@Override
	public void sayHelloWorld() {
		System.out.println("Hello World");
	}

}

JDK代理:

public class JdkProxyExample implements InvocationHandler {

	// 真实对象
	private Object target = null;

	/**
	 * 建立代理对象和真实对象的代理关系,并返回代理对象
	 * 
	 * @param target
	 * @return 代理对象
	 */
	public Object bind(Object target) {
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader()/* 类加载器 */, target.getClass().getInterfaces()/* 代理对象下挂在哪些接口下 */, this);
	}

	/**
	 * 代理方法逻辑
	 * 
	 * @param proxy
	 *            --代理对象
	 * @param method
	 *            --当前调度方法
	 * @param args
	 *            --当前方法参数
	 * @return 代理结果返回
	 * @throws Throwable
	 *             异常
	 */
	@Override
	public Object invoke(Object proxy/* 代理对象 */, Method method/* 调度的方法 */, Object[] args/* 调度方法的参数 */) throws Throwable {
		System.out.println("进入代理逻辑方法");
		System.out.println("在调度真实对象之前的服务");
		Object obj = method.invoke(target, args);// 相当于调用sayHelloWorld方法
		System.out.println("在调度真实对象之后的服务");
		return obj;
	}
}

我们来仔细分析一下这个代码
注意之前提到的两个步骤
1、建立代理对象和真实对象之间的关系
使用了build方法去完成,先用target保存真实对象,然后通过Proxy.newProxyInstance(target.getClass().getClassLoader()/* 类加载器 */, target.getClass().getInterfaces()来生成代理对象,这三个参数的含义如下:
1、第一个是类加载器
2、第二个是把生成的动态代理对象挂载在哪些接口下。这里的接口明显就是接口helloworld
3、第三个是定义实现方法逻辑的代理类,就是下面的invoke方法

2、第二步就是实现代理逻辑方法
即invoke方法

调用代理对象调度方法后,就进入到invoke里面Object obj=method.invoke(target,args)

测试代码:

public static void testJdkProxy() {
		JdkProxyExample jdk = new JdkProxyExample();
		// 绑定关系,因为挂在接口HelloWorld下,所以声明代理对象HelloWorld proxy
		HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
		// 注意,此时HelloWorld对象已经是一个代理对象,它会进入代理的逻辑方法invoke里
		proxy.sayHelloWorld();
	}

CGLIB

若没有接口,则用CGLIB进行,主要思想和JDK差不多,直接看代码:

public class CglibProxyExample implements MethodInterceptor {
	/**
	 * 生成CGLIB代理对象
	 * 
	 * @param cls
	 *            -- Class类
	 * @return Class类的CGLIB代理对象
	 */
	public Object getProxy(Class cls) {
		// CGLIB enhancer增强类对象
		Enhancer enhancer = new Enhancer();
		// 设置增强类型
		enhancer.setSuperclass(cls);
		// 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
		enhancer.setCallback(this);
		// 生成并返回代理对象
		return enhancer.create();
	}

	/**
	 * 代理逻辑方法
	 * 
	 * @param proxy
	 *            代理对象
	 * @param method
	 *            方法
	 * @param args
	 *            方法参数
	 * @param methodProxy
	 *            方法代理
	 * @return 代理逻辑返回
	 * @throws Throwable异常
	 */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.err.println("调用真实对象前");
		// CGLIB反射调用真实对象方法
		Object result = methodProxy.invokeSuper(proxy, args);
		System.err.println("调用真实对象后");
		return result;
	}
}

intercept就是其代理逻辑方法!

总结:

学习完反射和动态代理之后,我们对拦截器,之前只知道继承一个接口就可以实现的东西的理解更加深入,所谓的拦截器,不过都是动态代理模式下的所谓的“代理逻辑代码”罢了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值