【JAVAWEB学习笔记】25_基础加强:类加载器、注解 @xxx和动态代理

基础加强


学习目标


案例-自定义单元测试@MyTest

案例-全局的编码的解决

一、类加载器

1.什么是类加载器,作用是什么?

类加载器就加载字节码文件(.class)

2.类加载器的种类

类加载器有三种,不同类加载器加载不同的

1)BootStrap:引导类加载器:加载都是最基础的文件

2)ExtClassLoader:扩展类加载器:加载都是基础的文件

3)AppClassLoader:应用类加载器:三方jar包和自己编写java文件

怎么获得类加载器?(重点)

ClassLoader 字节码对象.getClassLoader();

public class Demo {

   public static void main(String[] args) {

      //获得Demo字节码文件的类加载器

      Class clazz = Demo.class;//获得Demo的字节码对象

      ClassLoader classLoader = clazz.getClassLoader();//获得类加载器

      //getResource的参数路径相对classes(src)

      //获得classes(src)下的任何的资源

      String path = classLoader.getResource("com/itheima/classloader/jdbc.properties").getPath();

      //classLoader.getResourceAsStream("");

      System.out.println(path);  

   }

}

二、注解 @xxx

1.什么是注解,注解作用

注解就是符合一定格式的语法 @xxxx

注解作用:

注释:在阅读程序时清楚----给程序员看的

注解:给jvm看的,给机器看的

注解在目前而言最主流的应用:代替配置文件

关于配置文件与注解开发的优缺点:

注解优点:开发效率高 成本低

注解缺点:耦合性大 并且不利于后期维护

企业的趋势:混合使用,不经常修改的可以用注解的形式。

2.jdk5提供的注解

@Override:告知编译器此方法是覆盖父类的

@Deprecated:标注过时

@SuppressWarnings:压制警告

deprecation,忽略过时

unused,忽略不使用

rawtypes,忽略类型安全

all,忽略所有

…..

发现的问题:

不同的注解只能在不同的位置使用(方法上、字段上、类上)

3.自定义注解(了解)

1)怎样去编写一个自定义的注解

2)怎样去使用注解

3)怎样去解析注解-----使用反射知识

(1)编写一个注解

关键字:@interface

注解的属性:

语法:返回值 名称();

注意:如果属性的名字是value,并且注解的属性值有一个 那么在使用注解时可以省略value

注解属性类型只能是以下几种

1.基本类型

2.String

3.枚举类型

4.注解类型

5.Class类型

6.以上类型的一维数组类型

(2)使用注解

在类/方法/字段 上面是@XXX

(3)解析使用了注解的类

介入一个概念:元注解:代表修饰注解的注解,作用:限制定义的注解的特性

@Retention

SOURCE: 注解在源码级别可见

CLASS:注解在字节码文件级别可见

RUNTIME:注解在整个运行阶段都可见

@Target

代表注解修饰的范围:类上使用,方法上使用,字段上使用

FIELD:字段上可用此注解

METHOD:方法上可以用此注解

TYPE:类/接口上可以使用此注解

注意:要想解析使用了注解的类 , 那么该注解的Retention必须设置成Runtime

关于注解解析的实质:从注解中解析出属性值

字节码对象存在于获得注解相关的方法

isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断该字节码对象身上是否使用该注解了

getAnnotation(Class<A> annotationClass) :获得该字节码对象身上的注解对象

4.案例-自定义单元测试@MyTest

public class MyTestParster {

   public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

      //获得TestDemo

      Class clazz = TestDemo.class;

      //获得所有的方法

      Method[] methods = clazz.getMethods();

      if(methods!=null){

         //获得注解使用了@MyTest的方法

         for(Method method:methods){

            //判断该方法是否使用了@MyTest注解

            boolean annotationPresent = method.isAnnotationPresent(MyTest.class);

            if(annotationPresent){

                //该方法使用MyTest注解了

                method.invoke(clazz.newInstance(), null);

            }

         }

      } 

   }

}

三、动态代理

1.什么是代理(中介)

目标对象/被代理对象 ------ 房主:真正的租房的方法

代理对象 ------- 黑中介:有租房子的方法(调用房主的租房的方法)

执行代理对象方法的对象 ---- 租房的人

流程:我们要租房----->中介(租房的方法)------>房主(租房的方法)

抽象:调用对象----->代理对象------>目标对象

2.动态代理

动态代理:不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时
的内存中动态生成代理对象。------字节码对象级别的代理对象

动态代理的API:

在jdk的API中存在一个Proxy中存在一个生成动态代理的的方法newProxyInstance


static Object


newProxyInstance(ClassLoader
loader,
Class<?>[]
interfaces,
InvocationHandler h)

返回值:Object就是代理对象

参数:loader:代表与目标对象相同的类加载器-------目标对

象.getClass().getClassLoader()

interfaces:代表与目标对象实现的所有的接口字节码对象数组

h:具体的代理的操作,InvocationHandler接口

注意:JDK的Proxy方式实现的动态代理 目标对象必须有接口 没有接口不能实现jdk版动态代理

例子一:

public class ProxyTest {

   @Test

   public void test1(){

      //获得动态的代理对象----在运行时 在内存中动态的为Target创建一个虚拟的代理对象

      //objProxy是代理对象 根据参数确定到底是谁的代理对象

      TargetInterface objProxy = (TargetInterface) Proxy.newProxyInstance(

            Target.class.getClassLoader(), //与目标对象相同的类加载器

            new Class[]{TargetInterface.class},

            new InvocationHandler() {

                //invoke 代表的是执行代理对象的方法

                @Override

                //method:代表目标对象的方法字节码对象

                //args:代表目标对象的响应的方法的参数

                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                   System.out.println("目标方法前的逻辑");

                   //执行目标对象的方法

                   Object invoke = method.invoke(new Target(), args);

                   System.out.println("目标方法后的逻辑");

                   return invoke;

                }

            }

         );

      objProxy.method1();

      String method2 = objProxy.method2();

      System.out.println(method2);

   }

}

例子二:

public class ProxyTest2 {

   public static void main(String[] args) {

      final Target target = new Target();

      //动态创建代理对象

      TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(

            target.getClass().getClassLoader(),

            target.getClass().getInterfaces(),

            new InvocationHandler() {

                @Override

                //被执行几次?------- 看代理对象调用方法几次

                //代理对象调用接口相应方法 都是调用invoke

                /*

                 * proxy:是代理对象

                 * method:代表的是目标方法的字节码对象

                 * args:代表是调用目标方法时参数

                 */

                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                   //反射知识点

                   Object invoke = method.invoke(target, args);//目标对象的相应方法

                   //retrun返回的值给代理对象

                   return invoke;

                }

            }

         );

      proxy.method1();//调用invoke---Method:目标对象的method1方法  args:null  返回值null

      String method2 = proxy.method2();//调用invoke---Method:目标对象的method2方法  args:null  返回值method2

      int method3 = proxy.method3(100);////调用invoke-----Method:目标对象的method3方法 args:Object[]{100}  返回值100

      System.out.println(method2);

      System.out.println(method3);
   }
}

3.案例-全局的编码的解决

public class EncodingFilter implements Filter{

   @Override

   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

         throws IOException, ServletException {

      final HttpServletRequest req = (HttpServletRequest) request;

      //使用动态代理完成全局编码

      HttpServletRequest enhanceRequset = (HttpServletRequest) Proxy.newProxyInstance(

            req.getClass().getClassLoader(),

            req.getClass().getInterfaces(),

            new InvocationHandler() {

                @Override

                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                   //对getParameter方法进行增强

                   String name = method.getName();//获得目标对象的方法名称

                   if("getParameter".equals(name)){

                      String invoke = (String) method.invoke(req, args);//乱码

                      //转码

                      invoke = new String(invoke.getBytes("iso8859-1"),"UTF-8");

                      return invoke;

                   }

                   return method.invoke(req, args);

                }

            }

         );

      chain.doFilter(enhanceRequset, response);

      //request.setCharacterEncoding("UTF-8");

      //在传递request之前对request的getParameter方法进行增强

      /*

       * 装饰者模式(包装)

       *

       * 1、增强类与被增强的类要实现统一接口

       * 2、在增强类中传入被增强的类

       * 3、需要增强的方法重写 不需要增强的方法调用被增强对象的

       *

       */

      //被增强的对象

      //HttpServletRequest req = (HttpServletRequest) request;

      //增强对象

      //EnhanceRequest enhanceRequest = new EnhanceRequest(req);

      //chain.doFilter(enhanceRequest, response);

   }

   @Override

   public void destroy() {

   }

   @Override

   public void init(FilterConfig filterConfig) throws ServletException {

   }

}

class EnhanceRequest extends HttpServletRequestWrapper{

   private HttpServletRequest request;

   public EnhanceRequest(HttpServletRequest request) {

      super(request);

      this.request = request;

   }

   //对getParaameter增强

   @Override

   public String getParameter(String name) {

      String parameter = request.getParameter(name);//乱码

      try {

         parameter = new String(parameter.getBytes("iso8859-1"),"UTF-8");

      } catch (UnsupportedEncodingException e) {

         e.printStackTrace();

      }

      return parameter;

   }

}
时间: 2024-10-18 06:35:13

【JAVAWEB学习笔记】25_基础加强:类加载器、注解 @xxx和动态代理的相关文章

JavaWeb学习笔记——jsp基础语法

1.JSP注释 显式注释 <!-- 注释内容 --> 隐式注释,隐式注释在客户端无法看见 // /* */ <% 注释内容 %> 2.Scriptlet(小脚本程序) 所有嵌入在HTML代码中的Java程序都必须使用Scriptlet标记起来,在JSP中一共有3种Scriptlet代码 3.Scriptlet标签

大话设计模式学习笔记——面向对象基础

前言 好记性不如烂"笔头"系列--大话设计模式学习笔记 目录 面向对象基础 面向对象基础 什么是类与实例 一切事物皆为对象,即所有的东西老师对象,对象就是可以看到.感觉到.听到.触摸到.尝到.或闻到的东西.准确地说,对象是一个自包含的实体,用一组可识别的特性和行为来标识.面向对象编程,英文叫 Object-Oriented Programming,其实就是针对对象来进行编程的意思.类就是具有相同属性和功能的对象的抽象集合.实例就是一个真实的对象.比如我们属于'人'类,而个人就是'人'类

Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用2

1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用. findClass protected Class<?> findClass(String name) throws ClassNotFoundException 使用指定的二进制名称查找类.此方法应该被类加载器的实现重写,该实现按照委托模型来加载类.在通过父

Java快速教程--vamei 学习笔记(基础篇)

链接:http://www.cnblogs.com/vamei/archive/2013/03/31/2991531.html java快速教程第1课 从HelloWorld到面向对象 学习网址:http://www.cnblogs.com/vamei/archive/2013/03/14/2958654.html java快速教程第2课 方法与数据成员 学习网址:http://www.cnblogs.com/vamei/archive/2013/03/25/2964430.html java快

C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字节的值,该如何在它上面调用方法? 二:值类型转换为引用类型--装箱 2.1CLR对值类型进行装箱时:新分配托管堆内存,将值类型的实例字段拷贝到新分配的内存中,返回托管堆中新分配对象的地址.这个地址就是一个指向对象的引用. int i = 10; Object obj = i; 三:将引用类型转换为值

[Golong]学习笔记(一) 基础知识

Go编程基础 Go的内置关键字(25个) 不多 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continute for import return var Go的注释方法(和js一样) 单行注释: // 多行注释: /**/ Go程序一般结构 common_structure.go 通过 pack

01-Python学习笔记-基础语法

Python标识符 -d           在解析时显示调试信息 -O           生成优化代码 ( .pyo 文件 ) -S           启动时不引入查找Python路径的位置 -v            输出Python版本号 -X           从 1.6版本之后基于内建的异常(仅仅用于字符串)已过时. -c cmd     执行 Python 脚本,并将运行结果作为 cmd 字符串. file           在给定的python文件执行python脚本. P

PHP:学习笔记(2)——基础语法

PHP:学习笔记(2)--基础语法 向屏幕输出 说明 1.void echo ( string $arg1 [, string $... ] ) 2.int print ( string $arg ) 注意: 1.echo.print 实际上不是一个函数(它是一个语言结构),因此你可以不必使用圆括号来括起它的参数列表. 2.输出变量的时候需要使用双引号! 3.int printf ( string $format [, mixed $args [, mixed $... ]] ) 4.strin

Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用

1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用. findClass protected Class<?> findClass(String name) throws ClassNotFoundException 使用指定的二进制名称查找类.此方法应该被类加载器的实现重写,该实现按照委托模型来加载类.在通过父