• 注解&动态代理


    注解&动态代理

    1.注解

    • 什么是注解

    Annotation,注解,是一种代码级别的说明,和类、接口、枚举在同一层次。

    • 注解作用
    1. 编译检查:让编译器实现基本的编译检查,如@Override
    2. 代码分析:对代码进行分析,从而达到取代xml的目的
    3. 编写文档:辅助生成帮助文档对应的内容

    1.1JDK提供的注解

    • @Deprecated

      表示被修饰的方法已经过时,过时的方法不建议使用,但仍可以使用。

      @Deprecated
      public void method1(){
      
      }
      
    • Override

      JDK5表示覆写父类的方法,JDK6还可以表示实现接口的方法。

      @Override
      public void start() {
          super.start();
      }
      
    • @SuppressWarnings("")

      表示抑制警告,被修饰的类或方法如果存在编译警告,将被编译器忽略。

      deprecation:忽略过时;

      rawtypes:忽略类型安全;

      unused:忽略不使用;

      unchecked:忽略安全检查;

      null:忽略空指针;

      all:忽略所有。

      //3.抑制警告
      //3.1deprecation,忽略过时警告
      //null,忽略str空指针
      @SuppressWarnings({"deprecation","null"})
      public void method2(){
          //3.2rawtypes,忽略类型安全警告,没有使用泛型
          //unused,忽略未使用警告
          @SuppressWarnings({"rawtypes","unused"})
          List list=new ArrayList();
          String str=null;
          str.toString();
      }
      

    1.2自定义注解

    • 定义注解
    public @interface MyAnno1 {
    }
    
    • 定义带属性的注解

    属性格式:修饰符 返回值类型 属性名() default 默认值;

    1. 修饰符默认且只能是public abstract
    2. 返回值类型:基本类型、字符串String、Class、注解、枚举,以及以上类型的一维数组
    3. 属性名自定义
    4. default 默认值:可省略
    public @interface MyAnno2 {
        String username() default "jack";
        int age();
        String[] strs();
        Class clazz() default Date.class;
        MyAnno1 myAnno();
        Color color();
    }
    enum Color{
        BLUE,RED,YELLOW
    }
    

    1.2.1使用自定义注解

    @MyAnno1
    @MyAnno2(
            username="tom",
            age=18,
            strs={"aaa","bbb","ccc"},
            clazz=String.class,
            myAnno=@MyAnno1,
            color=Color.RED
    )
    public class AnnotationDemo2 {
    
    }
    

    1.2.2解析自定义注解

    如果需要获得注解上设置的数据,那么就必须对注解进行解析,JDK提供java.lang.reflect.AnnotatedElement接口允许在运行时通过反射获得注解。

    1.3元注解

    用于修饰注解的注解,可以修饰自定义注解以及JDK提供的注解。

    1.4案例:自定义实现类似Junit@Test

    • MyJunitTest
    @Retention(RetentionPolicy.RUNTIME)
    //定义注解的时候,需要通过元注解Retention说明当前自定义注解的作用域(Class,Source,Runtime)
    @Target(ElementType.METHOD)
    //定义注解的时候,需要通过元注解Target说明当前的自定义注解的目标对象
    public @interface MyJunitTest {
        long timeout() default -1;//自定义属性,默认值为-1
    }
    /*
    @Retention和@Target这两个注解是必须的,否则Demo1中的method.isAnnotationPresent(MyJunitTest.class)结果一直都为false
    */
    
    • Demo1
    public class Demo1 {
        static{
            System.out.println("Demo1类被加载了");
        }
    
        @MyJunitTest(timeout=1000)
        public void method1(){
            System.out.println("--method1--");
        }
        
        @MyJunitTest
        public void method2(){
            System.out.println("--method2--");
        }
        @MyJunitTest
        public void method3(){
            System.out.println("--method3--");
        }
        public void method4(){
            System.out.println("--method4--");
        }
    }
    
    • Test1
    //找到Demo1的所有带有@MyJunitTest注解的方法
    public class Test1 {
        public static void main(String[] args) throws Exception {
            //1.将Demo1的字节码文件加载到内存,获取字节码文件在内存中的对象
            Class clazz=Class.forName("com.itheima.annotation2.Demo1");
            //2.获取Demo1及其父类的所有方法
            Method[] methods = clazz.getMethods();
            //3.遍历找出带@MyJunitTest注解的方法
            for (Method method:methods){
                if (method.isAnnotationPresent(MyJunitTest.class)){
                    method.invoke(new Demo1());
                    System.out.println(method.getName());
                }
            }
        }
    }
    

    2.动态代理

    Proxy.newProxyInstance(ClassLoader loader,Class<?> interfaces, InvocationHandler h);
    如:
        Proxy.newProxyInstance(EncodingFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    return null;
                }
            })
    

    2.1案例:解决get/post请求乱码问题

    • EncodingFilter
    @WebFilter("/*")
    public class EncodingFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            final HttpServletRequest request=(HttpServletRequest)servletRequest;
            HttpServletRequest requestProxy=(HttpServletRequest) Proxy.newProxyInstance(EncodingFilter.class.getClassLoader(),
                    request.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //指定增强getParameter方法,再分别根据post和get请求进行处理
                            if("getParameter".equals(method.getName())){
                                String requestMethod = request.getMethod();
                                System.out.println(requestMethod);
                                if("get".equalsIgnoreCase(requestMethod)){
                                    String value=(String) method.invoke(request,args);
                                    System.out.println("value"+value);
                                    return value;
                                    //return new String(value.getBytes("ISO-8859-1"),"UTF-8");//测试发现无需转码就没有乱码
                                }else{
                                    request.setCharacterEncoding("UTF-8");
                                    return method.invoke(request,args);
                                }
                            }else{
                                return method.invoke(request,args);
                            }
                        }
                    });
            filterChain.doFilter(requestProxy,servletResponse);
        }
    
        @Override
        public void destroy() {
        }
    }
    
  • 相关阅读:
    SQL中常用的数据类型及简介
    静态方法与非静态方法
    遍历多维数组
    遍历一个三维数组
    冒泡排序-方法2
    关于二分查找分
    冒泡排列-——方法1
    AngularJS 循环查询数组
    AngularJs 指令
    给定一个年月值,返回上个年月值,格式为:YYYY.MM string类型
  • 原文地址:https://www.cnblogs.com/ALiWang/p/13879307.html
Copyright © 2020-2023  润新知