代理
代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。
接口Business
public interface Business {
void execute();
}
接口实现类BusinessImp
public class BusinessImp implements Business {
public void execute() {
System.out.println("业务处理");
}
}
代理实现BusinessProxy
public class BusinessProxy implements Business {
private Business businessImp;
public BusinessProxy(Business businessImp) {
super();
this.businessImp = businessImp;
}
public void execute() {
System.out.println("业务处理前");
businessImp.execute();
System.out.println("业务处理后");
}
}
使用和结果
public class App
{
public static void main( String[] args )
{
Business businessImp=new BusinessImp();
BusinessProxy businessProxy=new BusinessProxy(businessImp);
businessProxy.execute();
}
}
输出:
总结:
1. 优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
2. 缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
JDK动态代理
jdk动态代理是由java内部的反射机制来实现的,需要实现类通过接口定义业务方法,利用JDK的API,动态的在内存中构建代理对象。
接口Business
public interface Business {
void execute();
}
接口实现类BusinessImp
public class BusinessImp implements Business {
public void execute() {
System.out.println("业务处理");
}
}
代理实现BusinessInvocationHandler
public class BusinessInvocationHandler implements InvocationHandler {
private Object target;
public BusinessInvocationHandler(Object target) {
super();
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("业务处理前");
Object result=method.invoke(target, args);
System.out.println("业务处理后");
return result;
}
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces(), this);
}
}
- 实现
InvocationHandler
接口,重写public Object invoke(Object proxy, Method method, Object[] args)
方法。 - 使用
Proxy
的static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
方法实现代理。ClassLoader loader
指定当前目标对象使用类加载器;Class<?>[] interfaces
是目标对象实现的接口的类型;InvocationHandler h
是事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。
使用和结果
public class App
{
public static void main( String[] args )
{
Business businessImp=new BusinessImp();
BusinessInvocationHandler businessInvocationHandler=new BusinessInvocationHandler(businessImp);
Business businessProxy=(Business)businessInvocationHandler.getProxy();
businessProxy.execute();
}
}
输出:
总结:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。
CGLIB动态代理
静态代理和JDK动态代理都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理。cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强。因为采用的是继承,所以不能对final修饰的类进行代理。
使用Maven导入相关jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
目标类BusinessImp
public class BusinessImp {
public void execute(){
System.out.println("业务处理");
}
}
代理实现BusinessProxy
public class BusinessProxy implements MethodInterceptor {
public Object getProxy(Class<?> clazz){
Enhancer enchancer=new Enhancer();
enchancer.setSuperclass(clazz);
enchancer.setCallback(this);
return enchancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("业务处理前");
Object result=proxy.invokeSuper(obj, args);
System.out.println("业务处理后");
return result;
}
}
- 实现
MethodInterceptor
接口,重写public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
方法,该方法为回调方法,在该方法中使用proxy.invokeSuper(obj, args)
执行目标对象的方法。 - 使用
Enhancer
来创建子类,setSuperclass(clazz)
方法设置了父类,setCallback(this)
方法设置了回调方法,create()
方法创建了子类。
使用和结果
public class App
{
public static void main( String[] args )
{
BusinessProxy businessProxy=new BusinessProxy();
BusinessImp businessImp=(BusinessImp) businessProxy.getProxy(BusinessImp.class);
businessImp.execute();
}
}
输出: