1. 程式人生 > 實用技巧 >註解&動態代理

註解&動態代理

註解&動態代理

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() {
    }
}