Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
优点:
一个是真正的你要访问的对象(目标类),另一个是代理对象,真正对象与代理
对象实现同一个接口,先访问代理类再访问真正要访问的对象。
静态代理:简单代理
代理者和被代理这需要是实现共同的接口,即我们的装饰模式
创建一个潘金莲对象,实现Kindweman接口,同时创建一个代理者王婆也实现这个接口
public class PJL implements KindWeman{
@Override
public void ShowEyes(Double money) {
System.out.println("PJL 拿到"+money+"元钱,showeyes");
}
@Override
public void DoSe(Double money) {
System.out.println("PJL 拿到"+money+"元钱,Dose");
}
}
public class WP implements KindWeman {
private KindWeman kw = null;
public WP(KindWeman kw ){
this.kw = kw;
}
@Override
public void ShowEyes(Double money) {
kw.ShowEyes(money);
}
@Override
public void DoSe(Double money) {
kw.DoSe(money);
}
}
潘金莲需要王婆的代理,代理者调用的方法都是被代理者的
public static void main(String[] args){
KindWeman KW = new PJL();
WP p = new WP(KW);
p.ShowEyes(3.0);
p.DoSe(6.0);
}
动态代理
动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。
动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。
动态代理生成技术:
1、jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象。
2、cglib (spring框架)
Java.lang.reflect.Proxy类可以直接生成一个代理对象,看例子,这里不需要王婆这个代理者,jdk给我们提供了。
@Test
public void test(){
KindWeman kw = new PJL();
//创建一个代理对象
//ClassLoader:类加载器。固定写法,和被代理类使用相同的类加载器即可。kw.getClass().getClassLoader()
//Class[] interface:代理类要实现的接口。固定写法,和被代理类使用相同的接口即可。kw.getClass().getInterfaces()
//InvocationHandler:策略(方案)设计模式的应用。如何代理?即代理的过程,你需要的操作
KindWeman KWproxy = (KindWeman)
Proxy.newProxyInstance(kw.getClass().getClassLoader(), kw.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//nvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行
//Object proxy:代理对象本身的引用。一般用不着。
//Method method:当前调用的方法。通过反射, KWproxy调用誰,这里的Method就是谁
//Object[] args:当前方法用到的参数
System.out.println("我是中间代理:需要收取费用");
Object o = method.invoke(kw, new Object[]{(Double) args[0] / 2});
System.out.println("事务完成,下次再来!");
return o;
}
});
KWproxy.ShowEyes(6.0);
KWproxy.ShowEyes(3.0);
}
使用这个思想,在我们前面讲到的业务层调用ThreadLocal管理,就不必要在servce层面上编写了。编写一个类来动态的获取服务,然后在代理当中添加ThreadLocal类实现事务的功能
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.itheima.service.AccountService;
import com.itheima.service.impl.AccountServiceImpl;
public class ObjectFactory {
//方法返回一个代理对象
public static AccountService getAccountService(){
final AccountService as= new AccountServiceImpl();
AccountService proxy = (AccountService) Proxy.newProxyInstance(as.getClass().getClassLoader(), as.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object invoke = null;
try {
ManagerThreadLocal.startTransacation();//begin
//执行的是真实对象的转账方法
invoke = method.invoke(as, args);
ManagerThreadLocal.commit();//提交事务
} catch (Exception e) {
try {
ManagerThreadLocal.rollback();//回滚事务
} catch (Exception e1) {
e1.printStackTrace();
}
}finally{
try {
ManagerThreadLocal.close();
} catch (Exception e) {
e.printStackTrace();
}//关闭
}
return invoke;
}
});
return proxy;
}
}
public void transfer(String fromname, String toname, double money) throws Exception {
// ad.updateAccount(fromname, toname, money);
AccountDao ad = new AccountDaoImpl();
//分别得到转出和转入账户对象
Account fromAccount = ad.findAccountByName(fromname);
Account toAccount = ad.findAccountByName(toname);
//修改账户各自的金额
fromAccount.setMoney(fromAccount.getMoney()-money);
toAccount.setMoney(toAccount.getMoney()+money);
//完成转账操作
ad.updateAccout(fromAccount);
int i = 10/0;
ad.updateAccout(toAccount);
}