jdk代理
- 通常说的动态代理就是指jdk代理。
- 通过jdk的api在运行期间,动态生成代理对象。
- 目标对象一定要实现接口。
- – java.lang.reflect.Proxy
- 作用:动态生成代理类和对象
- – java.lang.reflect.InvocationHandler(处理器接口)
- 可以通过invoke方法实现对真实角色的代理访问。
- 每次通过Proxy生成代理类对象对象时都要指定对应的处理器对象
interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
class RealStar implements Star {
@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket()");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney()");
}
@Override
public void confer() {
System.out.println("RealStar.confer()");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract()");
}
@Override
public void sing() {
System.out.println("RealStar(周杰伦本人).sing()");
}
}
class StarHandler implements InvocationHandler {
Star realStar;
public StarHandler(Star realStar) {
super();
this.realStar = realStar;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object object = null;
System.out.println("真正的方法执行前!");
System.out.println("面谈,签合同,预付款,订机票");
if(method.getName().equals("sing")){
object = method.invoke(realStar, args);
}
System.out.println("真正的方法执行后!");
System.out.println("收尾款");
return object;
}
}
class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Star.class}, handler);
proxy.sing();
}
}
/*实际生成的代理类
class ProxyStar implements Star {
StarHandler handler;
public ProxyStar(StarHandler handler) {
super();
this.handler = handler;
}
@Override
public void bookTicket() {
// handler.invoke(this,当前方法 , args);
}
@Override
public void collectMoney() {
// handler.invoke(this,当前方法 , args);
}
@Override
public void confer() {
// handler.invoke(this,当前方法 , args);
}
@Override
public void signContract() {
// handler.invoke(this,当前方法 , args);
}
@Override
public void sing() {
// handler.invoke(this,当前方法 , args);
}
}*/
cglib代理
也叫“子类代理”
当目标对象没有实现接口,就不能使用jdk代理,可以以子类的方式实现。
代理类通过执行回调类的intercept方法来对方法进行代理:
回调类需要实现的接口:MethodInterceptor
实现方法:intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy);
obj : 代理对象
method : 被代理对象的方法
args : 方法的参数
methodProxy : 代理对象的方法(与method的方法不同名,但是有对应关系,其方法实现与被代理对象对应方法的实现一致,而代理对象中与method同名的方法则被改写为:一部分判断逻辑和调用回调对象的intercept方法)
//目标类
class Dao{
public void save(){
System.out.println("模拟存储数据");
}
public void find(){
System.out.println("模拟查询数据");
}
}
//处理拦截器
class HandleInterceptor implements MethodInterceptor{
Object realDao;
public HandleInterceptor(Object realDao) {
super();
this.realDao = realDao;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//获取执行方法的方法名(用于判断)
String methodName = method.getName();
System.out.println("[---前置代理操作---]");
Object invoke = method.invoke(realDao, objects);
System.out.println("[---后置代理操作---]");
return invoke;
}
}
//代理工厂
class ProxyFactory {
//返回目标对象的代理对象
public static Object getProxyInstance(Object target) {
//多目标对象生成代理对象
//1.字节码生成工具
Enhancer enhancer = new Enhancer();
//2.设置代理对象的类型
enhancer.setSuperclass(target.getClass());
//3.设置回调方法(调用目标方法时触发)
enhancer.setCallback(new HandleInterceptor(target));
//4.创建对象并返回
return enhancer.create();
}
}
//测试
public class test {
@Test
public void test(){
Dao dao = new Dao();
Dao proxyInstance = (Dao)ProxyFactory.getProxyInstance(dao);
proxyInstance.save();
}
}
补充:
Cglib两种代理方式:
1、继承非持有式代理
创建代理过程(无需额外创建被代理的对象):
① 创建Enhancer对象
② 用Enhancer对象设置代理类的父类(被代理类)
③ 创建回调对象(回调类实现 MethodInterceptor 接口)
④ 用Enhancer对象设置回调对象
⑤ 用Enhancer对象创建代理对象
调用方式 :
在回调类的intercept函数中,执行:①前置输出 ②调用被代理对象的方法 ③后置输出
注意点:② 中需使用 methodProxy 对象调用 invokeSuper 方法即:methodProxy.invokeSuper(obj,args); 参数名意义在上边
2、继承持有式代理
创建代理过程 :
① 创建被代理对象
② 创建回调对象,并将被代理对象存入回调对象的target变量中
③ 使用Enhancer的create(Class clazz, MethodInterceptor callBack)方法创建代理对象
调用方式 :
在回调类的interpret函数中,执行:①前置输出 ②调用被代理对象的方法 ③后置输出
注意点:② 中需要使用 method对象调用invoke方法,即:method.invoke(target,args);参数名意义在上边。此处也可执行methodProxy.invokeSuper(obj, args); 但如此调用target对象就变得无意义,而且代理方式同1 继承非持有式代理没有区别了
区别:
在代理方式1中,在客户端(main函数)中,生成的代理类调用的方法内部如果有调用该类的方法时,会对被调用的方法进行代理。
而在代理方式2中,不会。
示例:
package com.cglib.test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.io.IOException;
import java.lang.reflect.Method;
public class TestMain {
public static void main(String[] args) throws InterruptedException, IOException {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestBean.class);
enhancer.setCallback(new TBProxy());
TestBean tb1 = (TestBean) enhancer.create();
TestBean tb2 = (TestBean) Enhancer.create(TestBean.class, new TBProxyx(new TestBean()));
tb1.print();
System.out.println("\n\n\n");
tb2.print();
}
// 被代理类
static class TestBean {
public void print() {
System.out.println("i am printing something");
t();
}
public void t() {
System.out.println("=== im t() ===");
}
}
// 代理方式1
static class TBProxy implements MethodInterceptor {
public TBProxy() {
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("============= start ================");
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("============= end ================");
return null;
}
}
// 代理方式2
static class TBProxyx implements MethodInterceptor {
public TBProxyx(Object obj) {
this.target = obj;
}
Object target;
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("============= startaaa ================");
Object result = method.invoke(target, args);
System.out.println("============= endaaa ================");
return result;
}
}
}
第一种,t()函数的打印结果上下有前后置输出,而第二种没有。
============= start ================
i am printing something
============= start ================
=== im t() ===
============= end ================
============= end ================
============= startaaa ================
i am printing something
=== im t() ===
============= endaaa ================