简单模拟下ssm,复习动态代理

来源:互联网 发布:java泛型类 编辑:程序博客网 时间:2024/06/05 23:40

最近在学ssm,好奇底层是怎么实现的

就根据现在所学的模拟了个,

顺便复习下动态代理,

时间紧,写的略渣

lib

dom4j-1.61.jar

xml

my.xml

<?xml version="1.0" encoding="UTF-8"?><peoples><people id="lihua"><property name="Name" value="lihua" type="java.lang.String"></property><property name="Age" value="19" type="java.lang.Integer"></property></people><people id="xiaomei"><property name="Name" value="xiaomei" type="java.lang.String"></property><property name="Age" value="19" type="java.lang.Integer"></property></people></peoples>

play.xml

<?xml version="1.0" encoding="UTF-8"?><plays><play id="sleep"><property value="10h" type="java.lang.String"></property></play><play id="eat"><property value="shi" type="java.lang.String"></property></play></plays>


用来模拟ioc根据配置文件创建对象

people.java

public interface People {public void eat(User u);public void sleep(User u);}

用来模拟动态代理根据配置文件实现mapper接口

User.java

public class User {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String toString() {return "user [name=" + name + ", age=" + age + "]";}}


main

import java.io.File;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;public class Test   {    public static void main(String[] args) throws Exception {        //模拟ioc,根据配置文件实例化对象         User u = newBean("xml/my.xml","lihua");                //模拟动态代理实现dao接口//只是纯接口的动态代理没加jdbc                 People daili = (People)daili("xml/play.xml",People.class);                daili.sleep(u);        daili.eat(u);    }        /**     * bean传给service根据 xml配置的事件动态代理dao接口     * @param path 配置文件地址     * @param c 需要代理的接口     * @return 代理实现的类     * @throws DocumentException     */    private static Object daili(String path,Class<?> c) throws DocumentException {//代理类        SAXReader reader = new SAXReader();        Document document = reader.read(new File(path));//参数1:配置文件位置        Element element = document.getRootElement();        List<Element> elements = element.elements("play");        final Map<String,Map<String,String>> map=new HashMap();//这里先遍历配置文件储存,因为用集合取数据方便,也可以边读接口边根据xml实现接口                Map<String,String> ma=null;        for (Element pl : elements) {            ma=new HashMap();            String name = pl.attributeValue("id");//方法名            List<Element> para = pl.elements("property");            for (Element p : para) {                String value = p.attributeValue("value");//参数值的string状态                String type = p.attributeValue("type");//参数类型的类                ma.put(value, type);            }            map.put(name, ma);                    }InvocationHandler h =new InvocationHandler() {                public Object invoke(Object proxy, Method method, Object[] args)                throws Throwable {            String name = method.getName();                            User u=(User)args[0];        Set<Entry<String,Map<String,String>>> set = map.entrySet();        for(Entry<String, Map<String, String>> entry:set){            if(entry.getKey().equals(name)&&name.contains("sleep")){                Set<Entry<String, String>> value = entry.getValue().entrySet();                for (Entry<String, String> v: value) {                    String para = v.getKey();//依次取出参数,这里只有一个就不判断了                    String type = v.getValue();//因为直接打印就不转换回去了,需要的话自行转换                    System.out.println(u.getName()+"今年"+u.getAge()+"岁,一天睡"+para);                }                            }            if(entry.getKey().equals(name)&&name.contains("eat")){                Set<Entry<String, String>> value = entry.getValue().entrySet();                for (Entry<String, String> v: value) {                    String para = v.getKey();//依次取出参数,这里只有一个就不判断了                    String type = v.getValue();//因为直接打印就不转换回去了,需要的话自行转换                    System.out.println(u.getName()+"今年"+u.getAge()+"岁,喜欢吃"+para);                }                            }        }                return null;                }};        return Proxy.newProxyInstance(Test.class.getClassLoader(), new Class<?>[]{c}, h);    }/** * 通过xml配置的id来实例化一个对象 * @param path xml位置 * @param id xml中的id * @return 实例化好的bean对象 * @throws Exception */    private static User newBean(String path,String id) throws Exception {        SAXReader reader = new SAXReader();        Document document = reader.read(new File(path));//参数1:配置文件位置        Element element = document.getRootElement();        List<Element> peoples = element.elements("people");        Element people=null;        for (Element peo : peoples) {            if(peo.attributeValue("id").equals(id))//参数1:id            people=peo;        }        if(people==null){            System.out.println("配置文件中无此id");            System.exit(0);        }        List<Element> attrs = people.elements("property");        Class<?> user = Class.forName("dydaili.User");        Method[] methods = user.getMethods();        Map<String,Class<?>[]> map=new HashMap();        for (Method method : methods) {//获取bean的所有方法和参数类型            String name = method.getName();            Class<?>[] parameters = method.getParameterTypes();            map.put(name, parameters);        }//后面有解释        User u=(dydaili.User) user.newInstance();        for (Element attr : attrs) {            String name = attr.attributeValue("name");//属性名            String value = attr.attributeValue("value");//属性的值            String type =attr.attributeValue("type");//属性类型            Constructor c1 = Class.forName(type).getDeclaredConstructor(String.class);//获取常用类型构造,把string转换为对应类型                        Method method = user.getMethod("set"+name,map.get("set"+name));//获取set方法,不用 Class.forName(type)而用map.get("set"+name)可以避免int和integer不匹配而找不到方法                        method.invoke(u, c1.newInstance(value));        }        return u;    }}

难点在反射实例化类时,set方法是int型而配置文件是integer,于是找不到set方法,只好先获取了所有方法信息,只根据方法名去找方法,配置文件给的类型只用来转换值的类型