JDK动态代理不仅可以代理有接口有实现类的情况,也可以代理只有接口没有实现类的情况。
有接口有委托类的情况
定义一个InvocationHandler接口的实现,用于增加额外功能逻辑
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyProxyHasDelegation implements InvocationHandler {
// 把委托对象传递进来进行增强
private Object object;
public MyProxyHasDelegation(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 判断是哪个接口的代理对象
String interf = method.getDeclaringClass().getName();
if("IBuyCar".equalsIgnoreCase(interf)) {
if(method.getName().equalsIgnoreCase("buyCar")) {
System.out.println("我是二手车中介@@@,请支付5000元服务费");
// 触发原来的业务逻辑
result = method.invoke(object,args);
System.out.println("我是二手车中介@@@,把委托人的信息卖钱,挣点外快");
}
}
if("IBuyHouse".equalsIgnoreCase(interf)) {
if(method.getName().equalsIgnoreCase("buyHouse")) {
System.out.println("我是二手房中介###,请支付5000元服务费");
// 触发原来的业务逻辑
result = method.invoke(object,args);
System.out.println("我是二手房中介###,把委托人的信息卖钱,挣点外快");
}
}
return result; // 如果原有业务逻辑有返回值别忘了返回
}
}
获取代理对象,并调用代理对象
public static void main(String[] args) {
//=====================获取IBuyHouse的代理对象===================
HouseDelegation houseDelegation = new HouseDelegation();
// 针对houseDelegation进行增强,获取代理对象
IBuyHouse iBuyHouse = (IBuyHouse)Proxy.newProxyInstance(houseDelegation.getClass().getClassLoader(),
houseDelegation.getClass().getInterfaces(),new MyProxyHasDelegation(houseDelegation));
// 使用代理对象的功能
iBuyHouse.buyHouse();
//=====================获取IBuyCar的代理对象===================
CarDelegation carDelegation = new CarDelegation();
// 针对carDelegation进行增强,获取代理对象
IBuyCar iBuyCar = (IBuyCar)Proxy.newProxyInstance(carDelegation.getClass().getClassLoader(),
carDelegation.getClass().getInterfaces(),new MyProxyHasDelegation(carDelegation));
// 使用代理对象的功能
iBuyCar.buyCar();
}
仅有接口的情况
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyProxyNoDelegation implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 判断是哪个接口的代理对象
String interf = method.getDeclaringClass().getName();
if("IBuyCar".equalsIgnoreCase(interf)) {
System.out.println("我是二手车中介@@@,请支付5000元服务费");
System.out.println("第一步:找车源");
System.out.println("第三步:车辆检查");
System.out.println("第二步:谈判");
System.out.println("第三步:车辆过户");
System.out.println("我是二手车中介@@@,把委托人的信息卖钱,挣点外快");
}
if("IBuyHouse".equalsIgnoreCase(interf)) {
System.out.println("我是二手房中介###,请支付5000元服务费");
System.out.println("第一步:找房源");
System.out.println("第二步:谈判");
System.out.println("第三步:房屋过户");
System.out.println("我是二手房中介###,把委托人的信息卖钱,挣点外快");
}
return null;
}
}
测试
public static void main(String[] args) {
Object object = Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{IBuyHouse.class, IBuyCar.class},
new MyProxyNoDelegation());
// 上面定义一次代理对象,下面针对两个接口都可以使用
((IBuyCar)object).buyCar();
((IBuyHouse)object).buyHouse();
}
总结
业务逻辑从无到有不也是一种增强嘛!是不是代理类不见了而且连实现类都不需要了呢?!就是我们Mapper动态代理的底层原理(只要定义接口,不需要写实现类)
Java中的动态代理包括JDK动态代理和CGLIB动态代理。使用这两种代理方式我们都可以不用定义代理类,区别在于使用JDK动态代理必须有一个接口类,使用CGLIB动态代理不需要接口类。
所以如果你要对一个实现了接口的类进行业务增强就用JDK动态代理,如果就对一个普通类进行业务增强就用CGLIB动态代理
cglib是第三方jar,因此需要引入坐标
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
比如有一个委托类(业务类),无需实现接口(当然,实现接口也可以,不影响)
public class Book {
public void addBook() {
System.out.println("新增图书...");
}
}
获取代理对象测试
public static void main(String[] args) {
Book book = new Book();
// 获取book对象的代理对象,
// Enhancer类似于JDK动态代理中的Proxy
// 通过实现接口MethodInterceptor能够对book中各个方法进行拦截增强,类似于JDK动态代理中的InvocationHandler
Book bookProxy = (Book)Enhancer.create(book.getClass(), new MethodInterceptor() {
Object obj = null;
// 和JDK动态代理的invoke方法一样,都是对业务逻辑的增强
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("日志开始........................");
obj = method.invoke(book,objects);
System.out.println("日志结束........................");
return obj;
}
});
bookProxy.addBook();
}
结果
cglib动态代理其实就是把原有对象传进去进行方法拦截,拦截到之后进行逻辑增强
你要清晰的明白
使用代理技术就是为了帮我们在不入侵原有代码的情况下增强业务逻辑
你完全可以使用静态代理一个一个去定义代理类,但是这样的话太过于繁琐
有接口就用JDK动态代理,没有接口就用CGLIB动态代理