1:动态代理
相对于静态代理,动态代理在创建代理对象上更加灵活,动态代理类的字节码在程序运行时,由java反射机制动态产生。它会根据需要,通过反射机制在程序运行期间,动态的为目标对象创建代理对象,无需程序员手动编写它的源码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类,代理的行为可以代理多个方法,即满足生产需要的同时,又达到代码通用的目的。
2:动态代理实现方式
- JDK动态代理:
- CGLIB动态代理
3:动态代理特点
- 目标对象不固定
- 在应用程序执行时动态创建目标对象
- 代理对象增强目标对象行为
4:动态代理-JDK动态代理
JDK动态代理的目标对象必须有接口存在。
1:动态代理类
Proxy.newProxyInstance(): 专门完成代理的操作类,可以通过此类为一个接口或多个接口动态的生成实现类,此类提供如下方法:
- 当前类加载器:this.getClass().getClassLoader()
- 目标角色实现的接口数组:目标角色.getClass().getInterfaces()
- InvocationHandler接口实现类:当前代理类实现InvocationHandler接口
public class JDKProxy implements InvocationHandler {
//因为不确定目标角色,所以是Object
private Object target;
//通过构造器,将目标角色传入
public JDKProxy (Object target){
this.target=target;
}
//获取代理类
public Object getProxy(){
//获取当前类的类加载器
ClassLoader classLoader=this.getClass().getClassLoader();
//获取目标角色实现的接口数组
Class[] interfaces=target.getClass().getInterfaces();
//一个实现InvocationHandler接口的类
/*
方式1:
InvocationHandler invocationHandler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
方式2:
当前类实现InvocationHandler接口
};*/
//得到代理实例
Object proxy=Proxy.newProxyInstance(classLoader,interfaces,this );
//返回代理实例
return proxy;
}
/**
* 实现InvocationHandler接口,重写invoke方法。
* @param proxy:调用该实例的代理实例
* @param method:目标对象的方法
* @param args:目标对象方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强目标行为
System.out.println("方法执行前");
/*
调用目标对象的方法
反射:invoke(Object obj,Object ...args)
obj:被调用方法的对象
args:被调用方法参数
*/
//使用Object结束方法返回值
Object invoke = method.invoke(target, args);
//增强目标行为
System.out.println("方法执行后");
//目标方法返回值
return invoke;
}
}
2:接口
接口1:
public interface BuyHouse {
void buyHouse();
}
接口2:
public interface BuyCar {
void buyCar();
}
接口3:带参,有返回值的方法
public interface BuyReturn {
String buyReturn(String str);
}
3:接口实现类
public class User implements BuyCar,BuyHouse,BuyReturn{
@Override
public void buyCar() {
System.out.println("买车");
}
@Override
public void buyHouse() {
System.out.println("买房");
}
@Override
public String buyReturn(String str) {
System.out.println("有参数有返回值的方法");
return "我是返回值";
}
}
4:测试动态代理
public class JDKProxyTest {
public static void main(String[] args) {
//被代理类对象
User user=new User();
//获取代理类,被代理类作为参数传入
JDKProxy jdkProxy=new JDKProxy(user);
//生成代理类对象
BuyCar buyCar=(BuyCar) jdkProxy.getProxy();
BuyHouse buyHouse=(BuyHouse) jdkProxy.getProxy();
BuyReturn buyReturn=(BuyReturn) jdkProxy.getProxy();
//调用共同行为
buyCar.buyCar();
buyHouse.buyHouse();
//接收返回值
String s = buyReturn.buyReturn(new String("我是参数"));
System.out.println(s);
}
}
5:CGLIB动态代理
CGLIB实现原理:为目标类生成一个子类(不能被final修饰类)
1:引入CGLIB依赖
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
2:代理类
public class CGLIBProxy implements MethodInterceptor{
//目标对象
private Object target;
//将目标对象作为参数传入
public CGLIBProxy(Object target){
this.target=target;
}
//获取代理对象
public Object getProxy(){
//调用Enhancer的create()方法,生成代理对象
Enhancer enhancer=new Enhancer();
//将目标对象设置为当前代理对象的父类
enhancer.setSuperclass(target.getClass());
//获取拦截器
/*
方式1:
MethodInterceptor methodInterceptor=new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return null;
}
};
方式2:
当前类实现接口:implements MethodInterceptor
*/
//设置拦截器
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 每当我们的代理实例被调用 都会执行intercept方法
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//增强行为
System.out.println("增强行为");
//调用目标对象方法
Object invoke = methodProxy.invoke(target, objects);
return invoke;
}
}
3:被代理类
public class People {
public void eat(){
System.out.println("吃饭");
}
}
4:测试CGLIB动态代理
public class CGLIBProxyTest {
public static void main(String[] args) {
//目标对象
People people=new People();
//代理类
CGLIBProxy cglibProxy=new CGLIBProxy(people);
//目标对象的代理对象
People proxy = (People)cglibProxy.getProxy();
//调用方法
proxy.eat();
}
}
六:JDK和CGLIB区别
- JDK动态代理实现接口,CGLIB动态代理继承思想
- JDK动态代理执行效率高于CGLIB动态代理
- 如果类实现接口则JDK动态代理,如果没有接口实现则CGLIB动态代理