JDK中的Proxy技术实现AOP功能

来源:互联网 发布:oracle数据库教程视频 编辑:程序博客网 时间:2024/04/29 22:33
JDK中的Proxy技术实现AOP功能
 很久没写日志了,今晚重温了一下传智播客的视频,动手使用JDK中的Proxy技术实现AOP功能。
       首先是准备一个接口PersonService及其实现类PersonServiceImpl。

       PersonService:
       public interface PersonService {
           public String getPersonName(Integer personid);
           public void save(String name);
           public void update(String name, Integer personid);
       }

       PersonServiceImpl
       import com.foreveross.service.PersonService;
            public class PersonServiceImpl implements PersonService {
           private String user = null;
           public PersonServiceImpl() {
    }
    public PersonServiceImpl(String user) {
         this.user = user;
    }
    public String getPersonName(Integer personid) {
        System.out.println("我是getPersonName方法");
        return "xxx";
    }
    public void save(String name) {
         System.out.println("我是save方法");
    }
    public void update(String name, Integer personid) {
         System.out.println("我是update方法");
    }
    public String getUser() {
         return user;
    }
       
       为什么要用到AOP技术呢?试想一下,如果上边的三个方法,要通过权限验证才能使用的话,那么要在每个方法里面都加上“if() {}"来判断吗?没错,这是可行的,但这里仅针对一个类,如果是N个类呢?大家可能想到,拦截器,但如果不是web项目呢?
       原理图如下:
            *******************************************************************
            **    客户端————>代理对象————>目标对象    **
            ******************************************************************* 
       客户端要调用目标对象之前,先要通过代理对象,再调用目标对象,代理对象实现了目标对象的所有方法。
       JDK中的Proxy技术实现AOP功能 - 彩笔 - 彩笔
        上图的代码使用JDK中的Proxy技术实现AOP功能。当我们要调用目标对象PersonServiceImpl的时候,先要通过JDKProxyFactory的createProxyInstance创建代理对象,这个代理对象会执行invoke的方法,里面判断是否有权限,有的话,再通过method.invoke,执行目标对象的方法。

       public class AOPTest {
   public static void main(String[] args) {
JDKProxyFactory factory = new JDKProxyFactory();
PersonService service = (PersonService)factory.createProxyInstance(new PersonServiceImpl("abc"));
service.save("john");
    }
       }
       
       上面的测试方法表明,如果传入了user,即user不为空,那么它就有权限执行save方法,打印出“我是save方法”,如果不传入user,即PersonService service = (PersonService)factory.createProxyInstance(new PersonServiceImpl());,那么,在代理对象的invoke方法中判断出没权限,不会扫行目标对象的save方法,所以没任何的输出。


/**
 * 第一个参数为目标代理加载器
Object o=   Proxy.newProxyInstance(AppTest.class.getClassLoader(),
 A.class.getInterfaces(), new InvocationHandler() {
     B a =   new A();
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
 
return   method.invoke(a, args);
}
});
   ((B)o).a() ;
    */


知识补充:

jvm在初期是将.java文件,编译成.class文件,当程序运行的时候,Java 虚拟机就将编译生成的 . class 文件按照需求和一定的规则加载进内存,组织成为一个完整的 Java 应用程序,jvm会把每个单独的类和接口编译成一个单独的.class文件,这些文件对于 Java 运行环境来说就是一个个可以动态加载的单元。我们可以在不重新编译其它代码的情况下,只编译需要修改的单元,并把修改文件编译后的 . class 文件放到 Java 的路径当中, 等到下次该 Java 虚拟机器重新激活时,这个逻辑上的 Java 应用程序就会因为加载了新修改的 .class 文件,自己的功能也做了更新,这就是 Java 的动态性。 
1. 预先加载与依需求加载 
Java 运行所需要的基本类采用预先加载,的方法全部加载要内存当中,因为这些单元在 Java 程序运行的过程当中经常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。 
我们在程序中需要使用自己定义的类的时候就要使用依需求加载方法。 

2. 隐式加载和显示加载 
程序中用 new 关键字来定义一个实例变量, JRE 在执行到 new 关键字的时候就会把对应的实例类加载进入内存,用的也很多, JRE 系统在后台自动的帮助用户加载,减少了用户的工作量,也增加了系统的安全性和程序的可读性。 
程序员自己写程序把需要的类加载到内存当中(显示加载) 
Class c = Class.forName("TestClass"); 
  TestClass object = (TestClass)c.newInstance
 
我们通过 Class 类的 forName (String s) 方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化 
Test test = new Test();//Test 类为自定义的一个测试类; 

ClassLoader cl = test. getClass().getClassLoader(); 

  // 获取 test 的类装载器; 

Class c = Class.forName("TestClass", true, cl); 

    因为一个类要加载就必需要有加载器,这里我们是通过获取加载 Test 类的加载器 cl 当作加载 TestClass 的类加载器来实现加载的。 



   3. 自定义类加载机制 
URL url = new URL("file:/d:/test/lib/"); 

  URLClassLoader urlCL = new URLClassLoader(new URL[]{url}); 

  Class c = urlCL.loadClass("TestClassA"); 

  TestClassA object = (TestClassA)c.newInstance(); 

  object.method(); 



首先定义 URL 指定类加载器从何处加载类, URL 可以指向网际网络上的任何位置,也可以指向我们计算机里的文件系统 ( 包含 JAR 文件 ) .上述范例当中我们从 file:/d:/test/lib/ 处寻找类;然后定义 URLClassLoader 来加载所需的类,最后即可使用该实例了。 
  4. 类加载器的阶层体系 
当执行hllo.class时候,java.exe会自动找到很显眼的jre位置,接着会在其中找到jvm.dll,(在jdk和jre中都有jvm)有了.dll文件之后激活jvm加载动态库,jvm活后,先做一些初始化的动作,比如说读取系统参数等。 
  然后,一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader (靴带机制,就是系上鞋带就要走路了), Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader .然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。 

这三个加载器就构成我们的 Java 类加载体系。他们分别从以下的路径寻找程序所需要的类: 

BootstrapLoader : sun.boot.class.path 

ExtClassLoader: java.ext.dirs 

AppClassLoader: java.class.path 

    这三个系统参量可以通过 System.getProperty() 函数得到具体对应的路径。大家可以自己编程实现查看具体的路径。  
0 0
原创粉丝点击