代理模式
概述:代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.
这样做的好处是:可以在目标对象实现的基础上,扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,
可以通过代理的方式来扩展该方法。
1、静态代理
装饰模式的实现。需要代理类和被代理类实现同一个接口。在代理类中设置被接口的引用,
通过构造的方式将被代理对象传入;在执行方法中扩展功能。
举例如下:
/**
* Iuser接口
*/
interface Iuser{
void print();
}
/**
* Iuser的实现类
*/
class UserImp implements Iuser{
public void print(){
System.out.println("实现类方法执行。。。");
}
}
/**
代理类
*/
class ProxyUser implements Iuser{
private Iuser iuser;
public ProxyUser(Iuser iuser){
this.iuser = iuser;
}
@Override
public void print() {
System.out.println("开启事务。。");
iuser.print();
System.out.println("提交事务。。");
}
}
public class Test {
@org.junit.Test
public void test1(){
UserImp userImp = new UserImp();
ProxyUser proxyUser = new ProxyUser(userImp);
proxyUser.print();
}
}
执行结果:
优点:可以在不修改已有的代码基础上扩展功能。
缺点:需要代理类与被代理类实现相同接口。这样类很多,同时,在接口更改时,需要维护的实现类也多。
2、动态代理
相对于静态代理,动态代理的代理类不需要实现接口,它是利用JDK的API动态在内存中创建代理对象。
只是需要指出被代理对象的接口类型。
举例如下:
被代理类同上
/**
动态代理类
*/
class ProxyFactory{
private Iuser target;
public ProxyFactory(Iuser target){
this.target = target;
}
public Object getProxyIuser(){
Object o = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
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;
}
});
return o;
}
}
@org.junit.Test
public void test2(){
Iuser userImp = new UserImp();
System.out.println(userImp.getClass());
userImp = (Iuser) new ProxyFactory(userImp).getProxyIuser();
System.out.println(userImp.getClass());
userImp.print();
}
执行结果:
动态代理需要被代理类最少实现一个接口,否则不能用动态代理。
3、Cglib代理
静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,
并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,
例如Spring AOP和synaop,为他们提供方法的interception(拦截)。
Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.
Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,
所以直接引入pring-core-3.2.5.jar
即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
举例如下:
/**
Cglib代理类
*/
class ProxyFactoryCglib implements MethodInterceptor{
//维护一个目标对象
private Object target;
public ProxyFactoryCglib(Object target){
this.target = target;
}
//给目标对象创建一个代理对象
public Object getProxyInstance() {
//工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建子类对象即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
Object invoke = method.invoke(target, objects);
System.out.println("提交事务");
return invoke;
}
}
/**
* 无接口被代理类
*/
class Student{
public void print(){
System.out.println("无接口执行了。。");
}
}
@org.junit.Test
public void test3(){
Student student = new Student();
student = (Student)new ProxyFactoryCglib(student).getProxyInstance();
student.print();
}
执行结果:
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理