MyBatis
上期我们讲了mapper代理来解决硬编码的问题,非常方便哈,但问题也随之出现了————MyBatis Mapper 接口没有实现类是怎么实现SQL查询的呢?
在思考这个问题之前,我们先来了解一下Java代理模式。
Java代理模式
1、静态代理:由我们手动创建编写的代理类,在执行代码之前就已经存在了。
2、动态代理:在程序运行时,通过反射机制动态创建完成的。
静态代理
老方法,先举个例子。现在有一个业务模块,采购和付钱两个业务(定义一个接口,里面有两个方法,但里没没有具体的实现内容)
interface Service {
void purchase();
void pay();
}
超市采购经理想承包下这个业务模块(说明采购经理要继承这个接口,并且给出买什么和付钱的具体方法)
class serviceImplA implements Service{
@Override
public String purchase(String a) {
System.out.println("采购东西");
return a ;
}
@Override
public int pay(int b) {
System.out.println("付钱");
return b;
}
}
但是这个采购经理(被代理对象 serviceImpl)不想(不能)直接参与这个业务,所以需要采购部门(其实就是代理对象 serviceProxy)并且此时采购部门可以给出更为具体的方法(代理对象可以扩展被代理对象的功能)。
class serviceProxy implements Service{
serviceImplA service = new serviceImplA();
@Override
public String purchase(String a) {
service.purchase(a);
System.out.println("采购"+a);
return null;
}
@Override
public int pay(int b) {
service.pay(b);
System.out.println(b+"元太贵了,价格低一点");
return 0;
}
}
来与批发商(就是测试用例 Test)进行这个业务模块。
public class Test {
public static void main(String[] args) {
Service service = new serviceProxy();
String a = "面包";
int b = 5;
String commodity = service.purchase(a);
int money = service.pay(b);
System.out.println(commodity);
System.out.println(money);
}
}
执行!
成功啦!但如果此时销售经理也承包了一个业务模块,销售和收钱呢?那我们还得再在找销售部门去帮销售经理去卖东西,就很不省钱(bushi)。
interface ServiceB {
String sales(String a);
int collect(int b);
}
class serviceImplB implements ServiceB{
@Override
public String sales(String a) {
System.out.println("销售东西");
return a ;
}
@Override
public int collect(int b) {
System.out.println("收钱");
return b;
}
}
class serviceProxyB implements ServiceB{
serviceImplB service = new serviceImplB();
@Override
public String sales(String a) {
service.sales(a);
System.out.println("销售"+a);
return null;
}
@Override
public int collect(int b) {
service.collect(b);
System.out.println(b+"元太便宜了,不能再便宜了");
return 0;
}
}
而且比如这次采购东西只要去告知批发商采购什么东西,而不用付钱,只需要采购部门负责告知批发商买什么的人来上班就行了,不需要付钱的人来上班,但部门的人都来干活了(静态代理的硬编码问题)总不能不给工资吧,那有没有更好的方法呢?Java动态代理!
动态代理
利用动态代理,我们对员工进行告知(让代理对象继承 InvocationHandler 接口)让采购部门的都不来上班,需要他们时我们就能精准的让告知(InvocationHandler 接口下的invoke(Object o, Method method, Object[] objects)方法:调用代理类的方法时,处理程序会利用反射,将代理类、代理类的方法、要调用代理类的参数传入这个函数,并运行这个函数,)需要来上班的人来上班就行了,就能省下钱了,嘿嘿。
interface Service {
String purchase(String a);
int pay(int b);
}
class serviceImplA implements Service {
@Override
public String purchase(String a) {
System.out.println("采购东西");
return a;
}
@Override
public int pay(int b) {
System.out.println("付钱");
return b;
}
}
class serviceProxy implements InvocationHandler{
private Service service;
public serviceProxy (Service service){
this.service=service;
}
public Object getServiceProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
var result = method.invoke(service, objects);
String methodName = method.getName();
if(methodName.equals("purchase")){
System.out.println("付钱的没来上班, 采购"+result);
} else if (methodName.equals("pay")) {
System.out.println("告知的没来上班, "+result+"元太贵了,价格低一点");
}
return result;
}
}
让来上班的人与批发商交流业务。
public class Test {
public static void main(String[] args) {
Service serviceA = new serviceImplA();
Service serviceA1 = (Service) new serviceProxy(serviceA).getServiceProxy();
String a = "面包";
int b = 5;
String count = serviceA1.purchase(a);
int money = serviceA1.pay(b);
System.out.println(count);
System.out.println(money);
}
}
执行!
成功!
我们继续来解决静态代理没解决的问题————销售经理也承包了一个业务模块,销售和收钱呢?
这时我们让两个部门合并一下(利用object)。
interface Service {
String purchase(String a);
int pay(int b);
}
class serviceImplA implements Service {
@Override
public String purchase(String a) {
System.out.println("采购东西");
return a;
}
@Override
public int pay(int b) {
System.out.println("付钱");
return b;
}
}
interface ServiceB {
String sales(String a);
int collect(int b);
}
class serviceImplB implements ServiceB {
@Override
public String sales(String a) {
System.out.println("销售东西");
return a;
}
@Override
public int collect(int b) {
System.out.println("收钱");
return b;
}
}
class serviceProxy implements InvocationHandler{
private Object service;
public serviceProxy (Object service){
this.service=service;
}
public Object getServiceProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
var result = method.invoke(service, objects);
String methodName = method.getName();
if(methodName.equals("purchase")){
System.out.println("我是采购部门告知的,付钱的和销售部门没来上班, 采购"+result);
} else if (methodName.equals("pay")) {
System.out.println("我是采购部门付钱的,告知的和销售部门没来上班, "+result+"元太贵了,价格低一点");
} else if (methodName.equals("sales")) {
System.out.println("我是销售部门卖货的的,收钱的和采购部门没来上班, 销售"+result);
} else if (methodName.equals("collect")) {
System.out.println("我是销售部门收钱的,卖货的和采购部门没来上班, "+result+"元太便宜了,价格不能再低了");
}
return result;
}
}
客户与批发商
public class Test {
public static void main(String[] args) {
//批发商
Service serviceA = new serviceImplA();
Service serviceA1 = (Service) new serviceProxy(serviceA).getServiceProxy();
String a = "面包";
int b = 5;
String commodity = serviceA1.purchase(a);
int money = serviceA1.pay(b);
System.out.println(commodity);
System.out.println(money);
//客户
ServiceB serviceB = new serviceImplB();
ServiceB serviceB1 = (ServiceB) new serviceProxy(serviceB).getServiceProxy();
String c = a;
int d = 7;
String sell = serviceB1.sales(c);
int count = serviceB1.collect(d);
System.out.println(sell);
System.out.println(count);
}
}