动态代理
一、特点
1、JDK反射库java.lang.reflect中提供了InvocationHandler接口和Proxy类,以实现动态代理,具体使用Proxy中的newProxyInstance()方法创建一个代理,其中需要实现第三个参数InvocationHandler接口。
2、动态代理基于接口实现
二、动态代理四要素
1、真正需要代理的接口
2、实现接口方法的实现类
2、代理对象
3、利用代理调用方法
注意:
1、代理需要增强的的方法都在接口里面,接口需要写在newProxyInstance()的第二个参数中
2、我们使用代理调用方法,其实是调用InvocationHandler()里面的invoke()方法
3、invoke()是一个回调方法,会使用反射调用对应方法
三、练习
尝试写一个生成代理的方法,并且通过代理调用方法
第一步:创建一个需要代理的接口
public interface UserMapper {
public String song();
public String dance(String name);
}
第二步:实现接口
import com.eva.mapper.UserMapper;
/**
* UserEntity实体类
*/
public class UserEntity implements UserMapper {
private String name;
public String song(){
return "正在唱歌";
}
public String dance(String name) {
return this.name+"在跳"+name;
}
public UserEntity() {
}
public UserEntity(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
第三步:写一个创建proxy代理对象的方法
import com.eva.entity.UserEntity;
import com.eva.mapper.UserMapper;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 创建代理的方法
*/
public class ProxyUtil {
/*
* 写一个静态方法用来创建代理对象
* 注意点:
* 1.newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)中的三个参数代表什么
* 参数一:用于指定用哪个类加载器,去加载生成的代理类 ProxyUtil.class.getClassLoader();
* 参数二:需要代理的对象(接口),可能有多个,需要的是有一个数组类型 new Class[]{UserMapper.class}
* 参数三:代理需要做的事,具体就是要代理哪些方法
* new InvocationHandler(){
* public Object invoke(Object proxy, Method method, Object[] args){
* 代理的方法都写在invoke方法里面,
* 我们调用代理方法的时候,实际就是调用InvocationHandler()里面的invoke()方法
* }
* }
* */
public static UserMapper createProxy(UserEntity userEntity) {
UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{UserMapper.class},
new InvocationHandler() {
/*
* invoke()是个回调函数,invoke()决定到底代理了哪些方法
* 当代理调用方法时,实际是调用invoke里面的方法
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* 参数一:proxy 代理对象
* 参数二:method 正在使用的代理方法
* 参数三:使用方法时传递的参数
* 返回值:代理的方法返回值
* */
return method.invoke(userEntity, args);
}
}
);
return userMapper;
}
}
第四步:创建一个测试类,来使用代理调用一下方法
import com.eva.entity.UserEntity;
import com.eva.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "e")
public class Test {
public static void main(String[] args) {
UserEntity userEntity = new UserEntity("甄嬛");
UserMapper proxy = ProxyUtil.createProxy(userEntity);
String dance = proxy.dance("惊鸿舞");
log.debug("{}",dance);
}
}