黑马程序员------------------代理类和AOP

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

代理

应用程序出了当前类能提供的功能外,有时需要一些其他的额外功能,比如安全、日志等,这时需要用代理类。

程序中的代理
    (1)要为已存在的多个具有相同接口的目标类的各个方法增加一系列的系统功能,例如,异常处理,日志、计算方法等的运行时间、事务管理等等,你如何做?
    (2)编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
    (3)如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理类,这样以后很容易切换。譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易。以后运行一段时间后,又想去掉系统功能也很容易。
   3.代理分为两种:静态代理和动态代理。 

<AOP>
  1.系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方法。
  2.交叉业务的房产问题即为面向方面的编程(AOP,Aspect oriented program),AOP的目标就是要
  使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编程切面代码的运行效果是一样的。
  3.使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。

.<代理模式>简单示例

目标类:   
 class X   
 {  
   void sayHello()  
   {  
     System.out.println("hello java");  
   }  
 }  
   
 代理类:  
XProxy  
 {  
   void sayHello()  
   {  
     starttime;  
     X.sayHello();  
     endTime;  
   }   
 }  


 

动态代理技术(JVM动态代理和CGLIB库动态代理)
         1.要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情。(引出动态代理)
         2.JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作 代理类 ,即动态代理类。
         3.JVM生成的动态类必须具有一个或多个接口,所以,JVM生成的动态类(Proxy)只能用作具有相同接口的目标类的代理。
         4.CGLIB库(一个开源库)可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的 类生成动态代理类,可以使用CGLIB库。
         5.代理类的各个方法中通除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下 四个位置加上系统功能代码:
      (1).在调用目标方法之前
      (2).在调用目标方法之后
      (3)在调用目标方法之前或之后
      (4)在处理目标方法异常的catch块中。

        6.创建JVM动态代理方法:

         方法一:获取动态类字节码(Class)--->用字节码获取Constructor---->用Constructor创建动态类实例

            a.使用Proxy获取动态类字节码(以Collection为例)

 

Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);  
System.out.println(clazzProxy1.getName());  


 

打印clazzProxy1的所有构造方法和成员方法。

System.out.println("----begin constructors list-------");  
        /* 
         * $Proxy0 
         * $Proxy0(InvocationHandler ,int) 
         */  
        printConstructors(clazzProxy1);  
          
        System.out.println("----begin methods list-------");          
        printMethods(clazzProxy1);<SPAN style="FONT-SIZE: 14px">         </SPAN>  


 

public static void printMethods(Class clazzProxy1) {  
        Method[] methods = clazzProxy1.getMethods();  
        for(Method method:methods){  
            String name = method.getName();  
            StringBuilder sBuilder = new StringBuilder(name);  
            sBuilder.append("(");  
            Class[] clazzParams = method.getParameterTypes();  
            for(Class clazzParam:clazzParams){  
                sBuilder.append(clazzParam.getName()).append(",");                
            }  
            if(clazzParams!=null &&clazzParams.length!=0)  
                sBuilder.deleteCharAt(sBuilder.length()-1);  
            sBuilder.append(")");  
            System.out.println(sBuilder);  
        }  
    }  
  
    public static void printConstructors(Class clazzProxy1) {  
        Constructor[] constructors=clazzProxy1.getConstructors();         
        for(Constructor constructor:constructors){  
            String name = constructor.getName();  
            StringBuilder sBuilder = new StringBuilder(name);  
            sBuilder.append("(");  
            Class[] clazzParams = constructor.getParameterTypes();  
            for(Class clazzParam:clazzParams){  
                sBuilder.append(clazzParam.getName()).append(",");                
            }  
            if(clazzParams!=null &&clazzParams.length!=0)  
                sBuilder.deleteCharAt(sBuilder.length()-1);  
            sBuilder.append(")");  
            System.out.println(sBuilder);  
        }  


 

实现AOP功能的封装和配置

功能描述:建立一个BeanFactory,可以根据配置文件中的bean名称到底一个JavaBean,如果bean的名字的是“ProxyFactoryBean”则返回ProxyFactoryBean根据配置文件中的".advice"和“.target”提供的目标和Advice返回的代理类。

1.ProxyFactoryBean类代码

package cn.itcast.test3.aopframework;  
import java.io.*;  
import java.util.Properties;  
import cn.itcast.test3.Advice;  
public class BeanFactory {  
    Properties prop = new Properties();  
    //创建对象时需要传入一个配置文件中的数据,所以需要在构造方法中接受一个参数   
    public BeanFactory(InputStream ips) {  
        try {  
            //将配置文件加载进来   
            prop.load(ips);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
    //创建getBean方法,通过配置文件中的名字获取bean对象   
    public Object getBean(String name){  
        //从配置文件中读取类名   
        String className = prop.getProperty(name);  
        Object bean = null;  
        try {  
            //由类的字节码获取对象   
            Class clazz = Class.forName(className);  
            bean = clazz.newInstance();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }   
        //判断bean是特殊的bean即ProxyFactoryBean还是普通的bean   
        if(bean instanceof ProxyFactoryBean){  
            Object proxy = null;  
            try {  
                //是ProxyFactoryBean的话,强转,并获取目标和通告   
                ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;  
                //获取advice和target   
                Advice advice = (Advice)Class.forName(prop.getProperty(name + ".advice")).newInstance();  
                Object target = Class.forName(prop.getProperty(name + ".target")).newInstance();  
                //设置目标和通告   
                proxyFactoryBean.setAdvice(advice);  
                proxyFactoryBean.setTarget(target);  
                //通过类ProxyFactoryBean(开发中是作为接口存在)中获得proxy对象   
                proxy = proxyFactoryBean.getProxy();  
            } catch (Exception e) {  
                // TODO Auto-generated catch block   
                e.printStackTrace();  
            }   
            //是ProxyFactoryBean的话,返回proxy对象   
            return proxy;  
        }  
        //否则返回普通bean对象   
        return bean;  
    }  
}  


 

2.BeanFacotry代码

import java.io.IOException;  
import java.io.InputStream;  
import java.util.Properties;  
  
import cn.itcast.day3.Advice;  
  
public class BeanFactory {  
    Properties prop =new Properties();  
      
    public BeanFactory(InputStream inStream){  
        try {  
            prop.load(inStream);  
        } catch (IOException e) {             
            e.printStackTrace();  
        }         
    }  
      
    public Object getBean(String name){  
        String className = prop.getProperty(name);  
        Class clazz=null;  
        Object bean=null;  
        try {  
            clazz = Class.forName(className);  
            bean = clazz.newInstance();  
        } catch (Exception e) {  
            // TODO Auto-generated catch block   
            e.printStackTrace();  
        }  
          
        if(bean instanceof ProxyFactoryBean){                     
            Object proxy = null;              
            try {  
                ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;   
                Advice advice = (Advice) Class.forName(prop.getProperty(className+".advice")).newInstance();  
                Object target =Class.forName(prop.getProperty(className+".target")).newInstance();  
                proxyFactoryBean.setAdvice(advice);  
                proxyFactoryBean.setTarget(target);  
                proxy = proxyFactoryBean.getProxy();  
            } catch (Exception e) {  
                // TODO Auto-generated catch block   
                e.printStackTrace();  
            }             
              
            return proxy;  
        }else{  
            return bean;              
        }         
    }  
  
}  


 

3.配置文件内容:

xxx=java.util.ArrayList  
#xxx=cn.itcast.day3.aopframework.ProxyFactoryBean  
xxx.advice=cn.itcast.day3.MyAdvice  
xxx.target=java.util.ArrayList  


 

4.框架测试类:

import java.io.InputStream;  
  
public class AopFrameworkTest {   
    public static void main(String[] args) {      
            InputStream ips =AopFrameworkTest.class.getResourceAsStream("config.properties");   <span class="comment">//读取配置文件的数据 </span><span> </span>
            BeanFactory beanFactory = new BeanFactory(ips);  
            Object bean =beanFactory.getBean("xxx");  
            System.out.println(bean.getClass().getName());    
    }  
}  



 

--------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流!---------------详细请查看: http://edu.csdn.net
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值