?????相信大家每天都在使用spring和mybatis,但是你們知道兩個(gè)框架是怎么整合的嗎?
?????回憶下我們?cè)陧?xiàng)目中使用的場(chǎng)景,我們首先會(huì)定義一個(gè)interface接口,接口上會(huì)一個(gè)@Mapper注解贝乎,代表的意思就是持久層。
@Mapper
public interface IptvInfoDAO {
@Select("select * from ${tableName} where loginaccount = #{userid} limit 1")
IptvInfo select(@Param("tableName") String tableName, @Param("userid") String userid);
}
?????接下來(lái)我們就會(huì)在service層叽粹,利用@Autowired 注解將Mapper注入,我們就可以對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作了览效。
@Service
public class IptvInfoService {
@Autowired
private IptvInfoDAO iptvInfoDAO;
public IptvInfo getIptvInfo(String userid) {
return iptvInfoDAO.select(TableUtil.getUserTable(userid), userid);
}
}
?????大家有沒(méi)有想過(guò)Mapper實(shí)際是一個(gè)接口,接口不可能實(shí)例化成一個(gè)對(duì)象虫几,將其對(duì)象放入IOC容器中锤灿,那為什么可以在Spring 容器中獲取一個(gè)對(duì)象,然后將對(duì)象賦給屬性呢辆脸?
?????帶著這樣的疑問(wèn)繼續(xù)往下看但校,有的小伙伴說(shuō)那肯定是Spring框架幫我們生成了一個(gè)代理對(duì)象,然后將代理對(duì)象放入到了IOC容器啡氢,自然我們就可以@Autowired依賴注入進(jìn)來(lái)状囱。沒(méi)錯(cuò)术裸,確實(shí)是這樣,原理太抽象啦,我們先通過(guò)一個(gè)簡(jiǎn)單的例子帶大家了解下兩個(gè)框架是如何整合的亭枷。
實(shí)戰(zhàn)演練
?????用到的技術(shù)有java自定義注解袭艺、java反射機(jī)制、jdk 的動(dòng)態(tài)代理,有不熟悉的小伙伴利用業(yè)余時(shí)間充下電吧
1)首先定義一個(gè)注解,給注解一個(gè)屬性sqlArr
package hchang.demo.annotate;
import java.lang.annotation.*;
/**
* @author lhc
* 1叨粘、注解本質(zhì)是一個(gè)接口
* 2猾编、注解的方法相當(dāng)于屬性
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface mySelect {
String [] sqlArr() default "";
}
2)定義一個(gè)interface接口,接口里面聲明一個(gè)方法升敲,方法上使用我們自定義的注解@mySelect
package hchang.demo.annotate;
public interface QryUserInfo {
@mySelect(sqlArr = "select password from I_IPTVINFO01 where loginAccount = 'kl333'; ")
String queryUserinfo();
}
3)利用JDK的動(dòng)態(tài)代理Proxy.newProxyInstance方法生成一個(gè)代理對(duì)象QryUserInfo答倡,當(dāng)代理對(duì)象的方法被調(diào)用時(shí),自動(dòng)執(zhí)行invoke()方法冻晤,將返回值返回到調(diào)用方法苇羡。
?????代理對(duì)象的三個(gè)參數(shù)分別是類(lèi)加載器、class接口數(shù)組鼻弧、InvocationHandler
package hchang.demo.annotate;
import hchang.demo.util.JDBCCon;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 手動(dòng)編寫(xiě)模擬實(shí)現(xiàn)Spring整合mybatis,與數(shù)據(jù)庫(kù)交互
* 1设江、自定義注解@mySelect
* 2、結(jié)合java反射機(jī)制獲取注解屬性值(sql語(yǔ)句)
* 3攘轩、結(jié)合java jdk動(dòng)態(tài)代理獲取接口的代理對(duì)象執(zhí)行sql語(yǔ)句
*/
public class AnnotateDemo {
public static void main(String[] args) {
QryUserInfo qryUserInfo = (QryUserInfo) Proxy.newProxyInstance(QryUserInfo.class.getClassLoader(), new Class[]{QryUserInfo.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
//獲取注解
mySelect ms = method.getAnnotation(mySelect.class);
//獲取注解的屬性值叉存,也就是SQL語(yǔ)句
String[] strings = ms.sqlArr();
//執(zhí)行SQL
JDBCCon jdbcCon = new JDBCCon();
Connection conn = jdbcCon.getConnection();
Statement stmt= null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
rs =stmt.executeQuery(strings[0]);
while (rs.next()) {
ret = rs.getString("password");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
finally {
if(conn !=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//返回值
return ret;
}
});
System.out.println(qryUserInfo.queryUserinfo());
}
}