黑马程序员 动态代理学习笔记二

----------android培训java培训、java学习型技术博客、期待与您交流!----------

创建代理
InvocationHandler接口
    创建实现Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数

    创建动态类的实例对象
       1)用反射获得构造方法
       2)编写一个简单的InvocationHandler类
       3)调用构造方法创建动态类的实例对象,并编写的InvocationHandler类的实例对象穿进去
      
     让JVM创建动态类及其实例对象,需要给它提供哪些信息?
     1)生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知
     2)产生的类字节码必须有一个关联的类加载器对象
     3)生成的类中的方法的代码是怎样的,也得由我们提供,把我们的代码写在一个约好的接口对象

InvocationHandler的运行原理
创建某一接口 MyInterface 的代理:
     1)
     InvocationHandler handler = new MyInvocationHandler(...);
            代理实例调用处理程序实现的接口,对代理实例调用方法时,将对方法调用进行编码并将其指

派到它的调用处理程序的 invoke 方法
     Class proxyClass = Proxy.getProxyClass(
         MyInterface.class.getClassLoader(), new Class[] { MyInterface .class });
            得到接口代理类的类加载器,要接口数组(因为可能要加载的不是一个接口)
     MyInterface myint = (MyInterface ) proxyClass.getConstructor(new Class[] {               

   InvocationHandler.class }).newInstance(new Object[] { handler });
            创建实例对象
     2)
     MyInterface myint = (MyInterface) Proxy.newProxyInstance(
         MyInterface .class.getClassLoader(),接口的类加载器
         new Class[] { MyInterface .class },要实现动态代理类的接口
         new InvocationHandler(){
              ArrayList target=new ArrayList();
              public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
                   Object retVal=method.invoke(target,args);
                   return target;此时target是Object类型,传入什么类型,我就是什么类型
              }
           }
         );匿名内部类

     为了增强框架功能,封装成一个对象
 
      objProxy.add("abc");方法,涉及到的三要素:objProxy对象、add方法、"abc"参数
      objProxy对象——>Object proxy
      add方法——>Method methods,继承Object只有hashCode,equals,toString这三个方法交给

handler
      "abc"参数——>Object[] args
      Class proxy${
             add(Object obj){
                 return handler.invoke(Object proxy,Method method,Object[] args);
             }
      }

三、简易Spring,对代理类进行封装
 
1)advice建议、协议
public interface Advice{
   void beforMethod(Method method);
   void afterMethod(Method method);
}
2)myAdvice用户自己定义的advice,和协议相符合,以便调用代理
public class myAdvice{
   public void beforMethod(Method method){
        定义自己的功能,或是广告
   }
   public void afterMethod(Method method){
        定义自己的功能,或是广告
   }
}
3)ProxyFactoryBean实现代理功能,进行的封装
public class ProxyFactoryBean {

 private Advice advice;
 private Object target;
 
        code…

        创建代理       
 public Object getProxy() {

        }

}
4)BeanFactory通过读取Properties,获取要代理的类的相关信息
public class BeanFactory {
 Properties props = new Properties();
 public BeanFactory(InputStream ips){
  try {
   props.load(ips);
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}


其实,通过认真学习张老师的视频教程,不难发现,动态代理的核心代码要素一个是代理的接口,该接口声明了代理的核心功能,另一个是java.lang.reflect.InvocationHandler接口,该接口的存在,主要是利用其中的public Object invoke(Objectproxy,Method method,Object[] args)函数的实现来实现代理接口中的方法,在调用被代理的接口中的方法时,该invoke方法就会被调用,且代理对象、所调用方法的Method对象及实际参数都会作为invoke方法的参数,例如:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyProxy {
	public static void main(String[] args) {
		Action action = (Action)Proxy.newProxyInstance(
				//代理接口的类加载器,或者某个类的加载器
				Action.class.getClassLoader(), 
				//代理类接口的Class
				new Class[]{Action.class}, 
				//InvocationHandler接口的实现
				new MyInvocationHandler()
				);
		
		/*每次调用代理时,都会调用MyInvocationHandler中的
		 * public Object invoke(Object proxy,Method method,Object[] args)这个方法
		 * 该方法对客户是半透明的,换句话说,就是客户知道的其实现了自己的要求,但是其中的其他业务逻辑(比如广告啊什么的),
		 * 用户是事先不知道的,我把这种情况称为半透明。*/
		
		/*调用代理的smile()方法实现Man类的smile()方法时,MyInvocationHandler中的invoke方法里的内容
		 * 都会执行,那么就自然会执行System.out.println("我是"+man.getName()+",我为自己代言");这条语句
		 * 从而打印“我是陈欧,我为自己代言”*/
		action.smile();
		action.speak();
	}

}

interface Action{
	void speak();
	void run();
	void smile();
}

class MyInvocationHandler implements InvocationHandler{
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		/*以下是广告阶段,哈哈...
		 * 其实,这就是AOP中的的那个切面
		 * */
		Man man = new Man();
		man.setName("陈欧");
		System.out.println("我是"+man.getName()+",我为自己代言");
		
		//执行代理对象所要代理的核心方法,这些方法才是客户的需求核心
		return method.invoke(man, args);
	}
}
class Man implements Action{
	private String name;
	private int aga;
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAga() {
		return aga;
	}

	public void setAga(int aga) {
		this.aga = aga;
	}

	@Override
	public void speak(){
		System.out.println("man can speak");
	}

	@Override
	public void run() {
		System.out.println("man can run");
	}

	@Override
	public void smile() {
		System.out.println("man can smile");
	}
	public void makeMoney(){
		System.out.println("赚钱");
	}
}


这里,还可以将其封装成一个获得动态代理的方法,如下所示:

Man类同上


public class MyProxy {
	public static void main(String[] args) {
		
		Action action = (Action)getProxy(new Man(),new Man());
		action.smile();
		action.speak();	
	}
	
	//注意,Man man可以是其他切面逻辑,这里为了简便,就用的是与代理目标target相同的类
	public static Object getProxy(final Object target,final Man man){
		
		Object proxy = Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), 
				new InvocationHandler(){

					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
					
					Man man = new Man();
					man.setName("陈欧");
					System.out.println("我是"+man.getName()+",我为自己代言");
					
					//执行代理对象所要代理的核心方法,这些方法才是客户的需求核心
					return method.invoke(target, args);
					}
					
				});
		return proxy;
		
	}
	
}

总结:动态代理听起来感觉很难,但是学起来确实感觉很有意思。




 

----------android培训java培训、java学习型技术博客、期待与您交流!----------

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值