1.1 project preparation
mybatis framework analysis
1.1. 1 project environment
- sqlMapConfig.xml core configuration file to remove DTD constraints. Because dom4j will go online to find DTD files.
- UserMapper.xml Mapping configuration file, remove DTD constraints.
- UserMapper interface.
- User entity class.
Import related jar packages
UserMapper.xml
5.1. 2 code implementation
- Create package CN guardwhy. framework.
- Create entity class: Mapper contains four attributes: namespace, ID, resulttype and SQL.
- Rewrite the toString() method to facilitate the post test to see the encapsulated results.
- Generate get and set methods, and a Mapper object represents a query statement object to be operated.
package cn.guardwhy.framework; /** * Encapsulate usermapper XML attribute */ public class Mapper { private String namespace; // Encapsulation interface name private String id; // Method name private String resultType; // Returns the entity class type private String sql; // SQL statement to execute /** * get.set method * @return */ public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getResultType() { return resultType; } public void setResultType(String resultType) { this.resultType = resultType; } public String getSql() { return sql; } public void setSql(String sql) { this.sql = sql; } @Override public String toString() { return "Mapper{" + "namespace='" + namespace + '\'' + ", id='" + id + '\'' + ", resultType='" + resultType + '\'' + ", sql='" + sql + '\'' + '}'; } }
5.2 dom4j method
Parse the XML file to get the Document object
1. Get input stream InputStream 2. new SAXReader().read(Input stream) return Document object
Document common methods
Method name | explain |
---|---|
Element getRootElement() | Get the root element (tag) in XML |
List<Node> selectNodes(String xpath) | Query multiple node nodes through xpath. Node is the parent interface of Element |
Node selectSingleNode(String xpath) | Get a node through xpath |
Element element(String name) | Get a child element of an element by its name |
Attribute text related methods
Method name | Function description |
---|---|
String attributeValue(String name) | Get the value of the attribute through the attribute name of the tag |
String getTextTrim() | Get the text content in the label and remove the spaces before and after |
5.3 core configuration file
Encapsulate the core configuration file: sqlmapconfig XML file
- Create four attributes: driver, URL, username and password
- Instantiate an empty Map collection: encapsulate the XML information of other mapping files
- Declare data source object DataSource
- Generate get and set methods and toString() methods
loadSqlMapConfig() method
1. Create the loadSqlMapConfig() method to
- Parsing sqlmapconfig XML Configuration file to assign values to the attributes in Configuration.
- Resolve usermapper XML configuration file to assign values to attributes in Mapper.
2. Calling method in construction method: loadSqlMapConfig()
5.3. 1 code implementation
Core profile
package cn.guardwhy.framework; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; import javax.sql.DataSource; import javax.xml.parsers.SAXParser; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Parsing XML file: sqlmapconfig xml, UserMapper. xml */ public class Configuration { // 1. Create connection pool properties private String driver; private String url; private String username; private String password; // 2. Define connection pool private DataSource dataSource; // 3. Instantiate an empty Map set: encapsulate the XML information of other mapping files private Map<String, Mapper> mappers = new HashMap<>(); // 4. call the method in the construction method: loadSqlMapConfig() public Configuration() { try { loadSqlMapConfig(); } catch (Exception e) { e.printStackTrace(); } } // 5. Method of parsing configuration file private void loadSqlMapConfig() throws DocumentException { // 5.1. Load / sqlmapconfig. From the classpath XML configuration file, creating input stream InputStream inputStream = Configuration.class.getResourceAsStream("/sqlMapConfig.xml"); // 5.2. Using dom4j to get the document object Document document = new SAXReader().read(inputStream); // 5.3. Use XPath to read all property elements List<Node> nodes = document.selectNodes("//property"); // 5.4. Traverse each property element and read its name and value attribute values for(Node node : nodes){ Element propertyElement = (Element) node; // Get the name attribute String name = propertyElement.attributeValue("name"); // Get value attribute String value = propertyElement.attributeValue("value"); // 6. Judge the string of name. If it is the same as the attribute name in the class, assign it to the corresponding attribute switch (name){ case "driver": this.driver = value; break; case "url": this.url = value; break; case "username": this.username = value; break; case "password": this.password = value; break; } } } /*** * set.get method * @return */ public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public Map<String, Mapper> getMappers() { return mappers; } public void setMappers(Map<String, Mapper> mappers) { this.mappers = mappers; } @Override public String toString() { return "Configuration{" + "driver='" + driver + '\'' + ", url='" + url + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + ", dataSource=" + dataSource + ", mappers=" + mappers + '}'; } }
Test code
package cn.guardwhy.test; import cn.guardwhy.framework.Configuration; public class TestFramework { public static void main(String[] args) { Configuration configuration = new Configuration(); System.out.println(configuration); } }
5.4 entity class mapping file
Resolve usermapper XML and encapsulated in Mapper class
- Create a new method loadMapper(Document document) and pass the current document object to the method
- Read the value of the resource attribute in < mapper >
- Read its corresponding XML file through resource
- Get the values of namespace, ID, resulttype and SQL and encapsulate them into Mapper objects
- Call this method in loadSqlMapConfig().
5.4. 3 code implementation
Parse configuration file
// Method of parsing configuration file private void loadSqlMapConfig() throws DocumentException { // Resolve usermapper XML file loadMapper(document); } /** * Parsing xml entity class mapping file * @param document */ private void loadMapper(Document document) throws DocumentException{ // 1. Read the resource attribute value in mapper // 1.1 read mapper element List<Node> nodes = document.selectNodes("//mapper"); // 1.2 traverse each mapper element for (Node node : nodes){ Element mapperElement = (Element) node; // 1.3 read the resource attribute value of mapper String resource = mapperElement.attributeValue("resource"); // 2. Parse the XML file to get the values of namespace, ID, resulttype and SQL // 2.1 use the class object to read the resource under the input stream InputStream inputStream = Configuration.class.getResourceAsStream("/" + resource); // 2.2 creating document objects Document doc = new SAXReader().read(inputStream); // 2.3 get root element Element rootElement = doc.getRootElement(); // 2.4 get the namespace attribute String namespace = rootElement.attributeValue("namespace"); // 2.5 read a select tag under the root element Element selectElement = rootElement.element("select"); // 2.6 get the id attribute String id = selectElement.attributeValue("id"); // 2.7 resultType attribute String resultType = selectElement.attributeValue("resultType"); // 2.8 SQL properties String sql = selectElement.getTextTrim(); // 3. Package as Mapper object // 3.1 create a custom Mapper object to encapsulate the above three attributes Mapper mapper = new Mapper(); mapper.setId(id); mapper.setResultType(resultType); mapper.setSql(sql); // 3.2 repackaging namespace attribute mapper.setNamespace(namespace); // 3.3 add the encapsulated mapper object to the mappers attribute of this, where the key is namespace + "+ ID, the value is a custom mapper object. String key = namespace + "." + id; this.mappers.put(key, mapper); } }
Test code
package cn.guardwhy.test; import cn.guardwhy.framework.Configuration; public class TestFramework { public static void main(String[] args) { Configuration configuration = new Configuration(); System.out.println(configuration); } }
5.5 creating data sources
- Create c3p0 a new data source. The data source class is ComboPooledDataSource.
- Set database related properties: driver, url,username,password.
- Set the dataSource of this as the data source object created above.
5.5. 2 code implementation
/** * 4.In the construction method, the method is called: * loadSqlMapConfig() * Call the createDataSource() method */ public Configuration() { try { loadSqlMapConfig(); createDataSource(); //create data source } catch (Exception e) { e.printStackTrace(); } } /** create data source */ private void createDataSource() throws PropertyVetoException { //Using c3p0 connection pool ComboPooledDataSource ds = new ComboPooledDataSource(); //Set the properties of the connection pool in the code ds.setUser(this.username); ds.setPassword(this.password); ds.setJdbcUrl(this.url); ds.setDriverClass(this.driver); //The created data source is assigned to the member variable this.dataSource = ds; }
5.6 core component SqlSession
Generation steps
- Write the SqlSession class and provide a getMapper() method to obtain the implementation object (proxy object) of the interface.
- Test: call the methods in the interface. The method of querying the database does not query from the database, but writes the simulated data in the code.
JDK dynamic proxy benefits
-
The proxy object of the interface is dynamically generated by the program during execution. We don't need to write a class to implement all the methods in the interface
-
You can dynamically generate objects with any interface
Methods in Proxy class
Proxy.newProxyInstance(): creates a dynamic proxy object for the UserMapper interface.
Parameter list: static object newproxyinstance (classloader, loader, class [] interfaces, invocationhandler h)
Role: dynamically generate proxy objects.
loader | The same class loader as the real object |
---|---|
interfaces | Interfaces implemented by proxy classes |
h | Call the interface of the proxy object, and pass in an implementation class when using. You need to rewrite the methods in the interface to realize the call of each method in the real object. |
return | Generate proxy object |
InvocationHandler interface
Object invoke(Object proxy, Method method, Object[] args)
Function: this method in the interface will be called multiple times, and each proxied method in the real object will be called once
proxy | For dynamically generated proxy objects, do not call them directly in methods, otherwise recursive dead loop calls will occur. |
---|---|
method | Methods of real objects |
args | Parameters passed when a proxy object calls a method |
return | Method |
invoke() method
method.invoke(Object obj, Object[] args) | Each method in a real object is called through reflection |
---|---|
Object obj | Real object |
Object[] args | Parameters passed when calling a real method |
Method signature
public <T> T getMapper(Class<T> type)
InvocationHandler anonymous class
Analysis diagram
basic function
- Get the Mapper object through the key.
- Get the SQL statement execution from the Mapper object and wrap it into an object return.
Generation steps
- Instantiate the Configuration object through the class full name + "+ Get the key for the method name.
- Get the value Mapper object through the key to get the sql statement to be executed and the returned entity type.
- Get the connection object through the data source, perform database operations, encapsulate the result set through reflection and return.
5.6.1 SqlSession class
Get SQL statement and return type
- Get the Map collection in Configuration
instantiation Configuration object adopt Configuration obtain Mapper Collection of objects
- Get the key in the Map: the full name of the class Method name
By method object->Get declared interface->Get the name: that is, the full name of the class com.itheima.dao.UserMapper Get the name of the currently executed method: findAllUsers Pass class full name+Method name get key
- Get the corresponding properties in Mapper
Pass class full name+"."+Method name, from mappers Mapped in mapper object from mapper Get the of the query from sql sentence from mapper Get return value type from resultType By reflection resultType The string is converted into a class object for later methods
Object Access database
- Get the data source through Configuration and the connection object through the data source
- Call the list queryforlist (connection, string SQL, class clazz) method
1. use JDBC Query data from database 2. Use reflection to instantiate clazz Object, and encapsulates all attributes and adds them to the collection.
Illustration:
5.6.2 JDBC access database
Create collection List Encapsulate result set without generics adopt Connection Connection object creates a precompiled statement object Execute the query to get the result set ResultSet
Encapsulate data into List objects
5.6. 3 code example
Session session class
package cn.guardwhy.framework; import javax.sql.DataSource; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Session class */ public class SqlSession { /** * Create a proxy object for the UserMapper interface * @param mapperClass Interface class object * @param <T> * @return */ public <T> T getMapper(Class<T> mapperClass){ return (T) Proxy.newProxyInstance(SqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() { /*** * * @param proxy Generated proxy object * @param method Method to call * @param args Method parameters * @return Return value: the return value of the method * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 1. Create Configuration object Configuration configuration = new Configuration(); // 2. Get the name of the method String id = method.getName(); // 3. Get the name of the interface String namespace = method.getDeclaringClass().getName(); // 4. Get the key value String key = namespace + "." + id; // 5. Get value Map<String, Mapper> mappers = configuration.getMappers(); Mapper mapper = mappers.get(key); // 6.SQL statement String sql = mapper.getSql(); // 7. Get the returned data type String resultType = mapper.getResultType(); // 8. Get its class object Class objClass = Class.forName(resultType); // 9. The Connection object is required to access the database DataSource dataSource = configuration.getDataSource(); Connection connection = dataSource.getConnection(); // Use JDBC to access the database and encapsulate it as list < user > List list = queryForList(connection, sql, objClass); return list; } }); } /** Use JDBC to access the database and encapsulate it as list < user > */ private List queryForList(Connection connection, String sql, Class clazz) throws Exception{ List users = new ArrayList<>(); // 1. Get the precompiled statement object through the connection object PreparedStatement ps = connection.prepareStatement(sql); // 2. Execute the SQL statement to get the result set ResultSet rs = ps.executeQuery(); // 3. Traverse the result set and encapsulate each row of records into a User object while (rs.next()){ Object user = clazz.getConstructor().newInstance(); // Get all member variables in the class Field[] fields = clazz.getDeclaredFields(); for (Field field : fields){ // Get the name of the member variable String name = field.getName(); // Traverse member variables and assign values to each member variable field.setAccessible(true); // Get all the data from the result set field.set(user, rs.getObject(name)); } // 4. Add to collection users.add(user); } rs.close(); ps.close(); connection.close(); // 5. Return set return users; } }
Test class
package cn.guardwhy.test; import cn.guardwhy.dao.UserMapper; import cn.guardwhy.domain.User; import cn.guardwhy.framework.Configuration; import cn.guardwhy.framework.SqlSession; import java.util.List; public class TestFramework { public static void main(String[] args) { // 1. Use SqlSession class SqlSession session = new SqlSession(); // 2. Call getMapper(UserMapper.class), and the proxy object will be returned UserMapper userMapper = session.getMapper(UserMapper.class); System.out.println(userMapper.getClass()); // 3. Call the method of the proxy object to get all users List<User> users = userMapper.findAllUsers(); // 4. Output user users.forEach(System.out::println); } }