【学习笔记】类加载器&注解&动态代理

本文深入探讨Java类加载器的工作原理,包括Bootstrap、ExtClassLoader和AppClassLoader的作用;详解注解的使用场景及自定义注解的创建;并介绍动态代理的实现方式及其在实际开发中的应用。

1.类加载器

(1)类加载器用于加载字节码文件(.class)

(2)类加载器的种类

三种:

  1. BootStrap:引导类加载器:加载的都是最基础的文件
  2. ExtClassLoader:扩展类加载器:加载都是基础的文件
  3. AppClassLoader:应用类加载器:第三方jar包和自己编写的java文件

(3)获得类加载器

字节码对象.getClassLoader()

2.注解

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

注释:在阅读程序时清楚----给程序员看的
注解:给jvm看的,给机器看的

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

关于配置文件与注解开发的优缺点:
注解优点:开发效率高 成本低 
注解缺点:耦合性大 并且不利于后期维护

(2)JDK5提供的注解

@Override:告知编译器此方法是覆盖父类的
@Deprecated:标注过时
@SuppressWarnings:压制黄线警告
不同的注解只能在不同的位置使用(方法上、字段上、类上)

(3)自定义注解(了解)

(3.1)

关键字:@interface
注解的属性:
语法:返回值 名称();
注意:如果属性的名字是value,并且注解的属性值有一个 那么在使用注解时可以省略value

package com.xing.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})//设置注解修饰的范围(类,方法,字段)
@Retention(RetentionPolicy.RUNTIME)//设置注解的可见级别
public @interface MyAnno {
	String name();

}

(3.2)

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

  • 基本类型
  • String
  • 枚举类型
  • 注解类型
  • Class类型
  • .以上类型的一维数组类型

(3.3)使用注解

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

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

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

@Retention:可见级别

SOURCE: 注解在源码级别可见

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

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

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

FIELD:字段上可用此注解

METHOD:方法上可以用此注解

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

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

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

字节码对象拥有获得注解的方法:

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

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

package com.itheima.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
	//注解的属性
	String name();
	int age() default 28;
	//String value();
	//String[] value();
	
	
}
package com.itheima.annotation;
@MyAnno(name = "zhangsan")
public class MyAnnoTest {
	
	@SuppressWarnings("all")
	@MyAnno(name = "zhangsan")
	//@MyAnno({ "aaa","bbb","ccc"})
	public void show(String str){
		System.out.println("show running...");
	}
	
}
package com.itheima.annotation;

import java.lang.reflect.Method;

public class MyAnnoParser {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException {
		
		//解析show方法上面的@MyAnno
		//直接的目的是 获得show方法上的@MyAnno中的参数
		
		//获得show方法的字节码对象
		Class clazz = MyAnnoTest.class;
		Method method = clazz.getMethod("show", String.class);
		//获得show方法上的@MyAnno
		MyAnno annotation = method.getAnnotation(MyAnno.class);
		//获得@MyAnno上的属性值
		System.out.println(annotation.name());//zhangsan
		System.out.println(annotation.age());//28
		
		//根据业务需求写逻辑代码
		
	}
	
}
模拟@Test
package com.itheima.case1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

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);//创建的对象调用method
				}
			}
		}
		
	}
	
}

3.动态代理

目标对象/被代理对象 ------ 房主:真正的租房的方法
代理对象 ------- 黑中介:有租房子的方法(调用房主的租房的方法)
执行代理对象方法的对象 ---- 租房的人

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

static Object

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

返回值:Object是代理对象
参数:loader:代表与目标对象相同的类加载器-------目标对象.getClass().getClassLoader()
interfaces:代表与目标对象实现的所有的接口的字节码对象数组
h:具体的代理的操作,InvocationHandler接口

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

package com.itheima.proxy;

public interface TargetInterface {

	public void method1();
	public String method2();
	public int method3(int x);
}
package com.itheima.proxy;
//被代理对象
public class Target implements TargetInterface{

	@Override
	public void method1() {
		System.out.println("method1 running...");
	}

	@Override
	public String method2() {
		System.out.println("method2 running...");
		return "method2";
	}

	@Override
	public int method3(int x) {
		return x;
	}

	
	
}
package com.itheima.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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);
		
	}
	
}

应用:通过动态代理增强request的getParameter方法,来解决get提交乱码问题。但实际开发中使用的是装饰着模式增强

package com.xing.encoding;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/encodingServlet")
public class EncodingServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/*//通过动态代理增强getParameter,解决post乱码
		HttpServletRequest enhanceRequest=(HttpServletRequest) Proxy.newProxyInstance(
				request.getClass().getClassLoader(), 
				request.getClass().getInterfaces(), 
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						if("getParameter".equals(method.getName())) {
							String invoke = (String) method.invoke(request, args);
							invoke=new String(invoke.getBytes("iso8859-1"),"utf-8");
							System.out.println("invoke:"+invoke);
							return invoke;
						}
						return method.invoke(request, args);//其他方法照原样返回
					}
				}
				);
		String name = enhanceRequest.getParameter("name");
		System.out.println(name);*/
		
		
		
		
		
		/*test
		 * String name = request.getParameter("name");//不乱码
		System.out.println("get:"+name);*/
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//通过装饰者模式增强getParameter
		EnhanceRequest req=new EnhanceRequest(request);
		String name = req.getParameter("name");//乱
		System.out.println("post"+name);
	}

}


class EnhanceRequest extends HttpServletRequestWrapper{

	private HttpServletRequest request;
	public EnhanceRequest(HttpServletRequest request) {
		super(request);
		this.request=request;
	}

	@Override
	public String getParameter(String name) {
		try {
			request.setCharacterEncoding("utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String parameter = request.getParameter(name);
		System.out.println("strong:"+parameter);
		return parameter;
	}
}



 

 

转载于:https://my.oschina.net/u/3943244/blog/1982265

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值