代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
介绍
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
静态代理模式
静态代理在使用时,需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口或者继承相同的父类。
比如访问数据库操作类
代码:
目标对象
public interface IUserDao {
void save();
}
实际对象
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("wwwwww");
}
}
代理对象
public class UserDaoProxy implements IUserDao {
private IUserDao target;
public UserDaoProxy(IUserDao target){
this.target=target;
}
@Override
public void save() {
// TODO Auto-generated method stub
target.save();
}
}
客户端
public static void main(String[] args) {
// 目标对象
UserDao userDao =new UserDao();
//代理对象
UserDaoProxy proxy =new UserDaoProxy(userDao);
proxy.save();
}
静态代理模式优缺点:
1:可以在不修改目标对象的功能前提下,对目标功能扩展
2:缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象与代理对象都要维护。(可以使用动态代理)
动态代理模式
动态代理有以下特点:
1:代理对象,不需要实现接口
2:代理对象的生成,是利用jdk的API,动态在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口类型)
3:动态代理也叫:jdk代理,接口代理
jdk中生成代理对象的API
代理类所在包:java.lang.reflect.Proxy
JDk实现代理只需要newProxyInstance方法,但是该方法需要接受三个参数
Static Object newProxyInstance(ClassLoader loader,Class
public class ProxyFactory {
//维护一个目标对象
private Object target;
public ProxyFactory(Object target){
this.target = target ;
}
//给目标对象生成代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行目标方法
Object returnVaObject=method.invoke(target, args);
return returnVaObject;
}
});
}
}
客户端
public class AppTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
IUserDao targetDao =new UserDao();
IUserDao proxyDao =(IUserDao)new ProxyFactory(targetDao).getProxyInstance();
proxyDao.save();
}
}
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。
Cglib代理模式
上面静态代理和动态代理都是要求目标对象是实现一个接口的目标对象,但有时目标对象只是一个普通类,并没有实现任何接口,这时候可以考虑使用以目标对象子类的方式类实现代理。
Cglib代理也叫子类代理,他是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
1:jdk动态代理有一个限制,即目标对象必须实现一个或多个接口,如果想代理没有实现接口的目标对象就要使用Cglib代理。
2:Cglib是一个强大的高性能的代码生成包,可以运行期扩展java类与实现java接口。
Cglib子类实现方法
1:需要引入Cglib的jar文件,但是Spring核心包中已经包括Cglib功能
2:引入功能包后,就可以在内存中动态构建子类
3:代理的类不能为final,否则报错
4:目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。
目标对象
public class UerDao {
public void save() {
System.out.println("wwwwww");
}
}
代理工厂
public class ProxyFactoryCglib implements MethodInterceptor {
//维护目标对象
private Object targetObject;
public ProxyFactoryCglib( Object targetObject) {
this.targetObject =targetObject ;
}
public Object getProxyInstance(){
//工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(targetObject.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建子类(代理对象)
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] args,
MethodProxy arg3) throws Throwable {
Object returnvalue= method.invoke(targetObject, args);
return returnvalue;
}
}
客户端
public class AppTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
UerDao dao = new UerDao();
UerDao proxyDao2=(UerDao)new ProxyFactoryCglib(dao).getProxyInstance();
proxyDao2.save();
}
}