JDK动态代理
上一篇博文静态代理介绍了静态代理的简单实现,以及静态代理的缺点:
- 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
- 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。
JDK动态代理的优点
- 代理对象不需要实现接口,这样就不会有众多的代理类;
- 利用JDK生成代理对象,动态地在内存中构建代理对象,即在程序运行时,通过反射机制动态生成;
- 不需要事先知道要代理的是什么,只有在运行时才确认;
JDK动态代理缺点
- 目标类必须实现的某个接口,如果某个类没有实现接口则不能生成代理对象;
- 只能代理接口,要代理类需要使用第三方的CLIGB等类库;
JDK动态代理实例演示
- 创建接口:Animal
public interface Animal {
void printName();
}
- 创建目标对象Dog并实现接口Animal
@Component
public class Dog implements Animal {
@Override
public void printName() {
System.out.println("===== I am a dog ====");
}
}
- 创建代理代理类JDKProxy获取代理对象
@Component
public class JDKDogProxy {
@Autowired
private Dog dog; // 创建目标对象
public Animal getJDKProxy() {
// 参数一:ClassLoader loader,指定使用哪个类装载器生成代理对象,一般用代理类的类加载器;
// 参数二:Class<?>[] interfaces,通过指定接口来指定哪个对象的代理对象,即指定代理类实现的接口;
// 参数三:InvocationHandler h,通过实现handler的invoke方法来指定要在代理对象的方法里做什么事;
return (Animal) Proxy.newProxyInstance(Dog.class.getClassLoader(), Dog.class.getInterfaces(), (Object proxy, Method method, Object[] args) -> {
if (method.getName().equals("printName")) {
System.out.println("++++ 调用目标方法前处理 ++++");
method.invoke(dog, args);
System.out.println("++++ 调用目标方法后处理 ++++");
}
return null;
});
}
}
- 测试动态代理
@SpringBootTest
@RunWith(SpringRunner.class)
public class ProxyTest {
@Autowired
private JDKDogProxy jdkDogProxy;
@Test
public void testJDKProxy() {
Animal dog = jdkDogProxy.getJDKProxy();
dog.printName();
}
}
- 运行结果