1、什么是动态代理
动态代理利用Java的反射技术(Java Reflection)生成字节码,在运行时创建一个实现某些给定接口的新类(也称"动态代理类")及其实例。
注意:这里代理的是接口,不是类和抽象类。
2、动态代理的应用场景
一个接口的实现在编译时无法知道,需要在运行时才能实现
Dubbo、Dubbo中动态代理的使用
AOP in Spring
3、JDK动态代理步骤
Proxy.newInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
1)创建一个实现InvocationHandler接口的类,它必须实现invoke()方法。
2)创建被代理的类及接口。
3)调用Proxy的静态方法,创建一个代理类。
4)通过代理调用方法。
//懒,就写一起了
public class MainTest {
//测试方法
public static void main(String[] args) throws Exception {
MainTest mainTest = new MainTest();
mainTest.test();
//MyInvocationHandler类的invoke方法进入
//我是汽车
//MyInvocationHandler类的invoke方法退出
}
public void test() {
//调用Proxy的静态方法,创建一个代理类
InvocationHandler handler = new MyInvocationHandler(new Car());
IProduct iProduct = (IProduct) Proxy.newProxyInstance(IProduct.class.getClassLoader(),
new Class[]{IProduct.class},
handler);
//参数1:类加载器(Class Loader)
//参数2:需要实现的接口数组
//参数3:InvocationHandler接口。
//(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)
//创建代理类$Proxy0,$Proxy0类实现了interfaces的接口,并继承了Proxy类
//(2)实例化$Proxy0并在构造方法中把handler传过去,接着$Proxy0调用父类
//Proxy的构造器,为h赋值,如下:
//class Proxy{
// InvocationHandler h=null;
// protected Proxy(InvocationHandler h) {
// this.h = h;
// }
// ...
//}
//通过代理调用方法
iProduct.show();
}
//创建一个实现InvocationHandler接口的类,必须实现invoke()方法
public class MyInvocationHandler implements InvocationHandler {
private IProduct iProduct;
public MyInvocationHandler(IProduct iProduct) {
this.iProduct = iProduct;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("MyInvocationHandler类的invoke方法进入");
Object invoke = method.invoke(iProduct, args);
System.out.println("MyInvocationHandler类的invoke方法退出");
return invoke;
}
}
//被代理的类
public class Car implements IProduct {
@Override
public void show() {
System.out.println("我是汽车");
}
}
//被代理的接口
public interface IProduct {
void show();
}
}
4、jdk动态代理为什么只能代理接口
因为生成的代理类本身已经继承了Proxy类,java是不允许多继承。
5、jdk 动态代理核心思想
通过实现被代理类的所有接口,生成一个字节码文件后构造一个代理对象,通过持有反射构造被代理类的一个实例,
再通过invoke反射调用被代理类实例的方法,来实现代理。
6、网上一个使用动态代理,获取配置文件的代码示例
#rescouces下的config文件夹下的
#config.properties文件
db.url = db.url1
db.validation = true
db.pool.size = 300
//懒,就写一起了
public class MainTest {
//测试方法
public static void main(String[] args) throws Exception {
MainTest mainTest = new MainTest();
mainTest.test();
}
public void test() throws IOException {
InputStream is = this.getClass().getResourceAsStream("/config/config.properties");
//创建代理类
IConfig config = ConfigFactory.create(is);
System.out.println("config.noCheck():"+config.noCheck());
System.out.println("config.dbUrl():"+config.dbUrl());
System.out.println("config.isValidated():"+config.isValidated());
System.out.println("config.poolSize():"+config.poolSize());
}
public static final class ConfigFactory {
public static IConfig create(final InputStream is) throws IOException {
final Properties properties = new Properties();
properties.load(is);
return (IConfig) Proxy.newProxyInstance(IConfig.class.getClassLoader(),
new Class[]{IConfig.class}, new PropertyMapper(properties));
}
public static final class PropertyMapper implements InvocationHandler {
private final Properties properties;
public PropertyMapper(Properties properties) {
this.properties = properties;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//查看是否有Value注解
final Value value = method.getAnnotation(Value.class);
if (value == null) return null;
//获取配置的值
String property = properties.getProperty(value.value());
if (property == null) return (null);
final Class<?> returns = method.getReturnType();
//8种基本类型的时候为 true,其他为false
if (returns.isPrimitive()) {
if (returns.equals(int.class)) return (Integer.valueOf(property));
else if (returns.equals(long.class)) return (Long.valueOf(property));
else if (returns.equals(double.class)) return (Double.valueOf(property));
else if (returns.equals(float.class)) return (Float.valueOf(property));
else if (returns.equals(boolean.class)) return (Boolean.valueOf(property));
}
return property;
}
}
}
public interface IConfig {
String noCheck();
@Value("db.url")
String dbUrl();
@Value("db.validation")
boolean isValidated();
@Value("db.pool.size")
int poolSize();
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}
}
7、cglib
cglib 动态代理含义:
使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类。
cglib 动态代理缺点:
不能代理final修饰的类。
cglib核心思想:
通过生成子类字节码实现,代理类为每个委托方法都生成两个方法,
以add方法为例,一个是重写的add方法,一个是CGLIB$add0方法,该方法直接调用委托类的add方法。