支撑Spring的基础技术:反射,动态代理,cglib等

来源:互联网 发布:网络打印机搜索不到 编辑:程序博客网 时间:2024/06/02 04:12

1.静态代码块和非静态代码块以及构造函数

public class Parent {    static String name = "hello";    //非静态代码块    {        System.out.println("1");    }    //静态代码块    static {        System.out.println("2");    }    public Parent() {        System.out.println("3");    }}

public class Child extends Parent {    static String childName = "hello";    {        System.out.println("4");    }    static {        System.out.println("5");    }    public Child() {        System.out.println("6");    }}
调用测试

public class StaticCodeBlockOrderTest {    public static void main(String[] args) {        new Child();    }}

对象的初始化顺序:
首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,
如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。
子类的非静态代码块执行完毕再去执行子类的构造方法。

参考:java中静态代码块的用法 static用法详解

静态代码块的应用

需要一个Util类,需要系统初始化的时候就初始化一个hashMap,部分代码省略以...代替

    private static Map<String, List<String>> smap = new HashMap<String, List<String>>();    static {        for (int i = 0; i < k; i++) {            List<String> ls = new ArrayList<String>();            ls.add(...);            ls.add(...);            smap.put(..., ls);        }    }

这个一样的用法:Map的静态赋值 


2.泛型 Class<T>和Class<?>的差异

public class Box<T> {    private T t;    public Box(){    }        public Box(T data){        this.t=data;    }        public T getT() {        return t;    }    public void setT(T t) {        this.t = t;    }}
调用

    public static void main(String[] args) {        Box<String> s=new Box<String>("abc");        Box<Integer> i=new Box<Integer>(123);        System.out.println("s class:" + s.getClass());        System.out.println("i class:" + i.getClass());        System.out.println(s.getClass() == i.getClass());}
输出


为什么有Class<T>还需要Class<?>呢?

其实看这个就明白了
在其他类中例如这个Test里,你可以定义

    public static void getData(Box<String> data){        System.out.println("data :" + data.getT());    }

也可以定义

    public static void getData(Box<Integer> data){        System.out.println("data :" + data.getT());    }


但是你要是同时定义这2个就会报错

名称冲突: getData(Box<Integer>)和getData(Box<String>)具有相同疑符



使用通配符?就可以解决这个问题

public class TestMain {    public static void main(String[] args) {        Box<String> s=new Box<String>("abc");        Box<Integer> i=new Box<Integer>(123);        System.out.println("s class:" + s.getClass());        System.out.println("i class:" + i.getClass());        System.out.println(s.getClass() == i.getClass());        getData(s);        getData(i);    }        public static void getData(Box<?> data){        System.out.println("data :" + data.getT());    }}



参考:

Java总结篇系列:Java泛型

java中的泛型总结


再来看看Class<?>的用处

public class TestMain {    public static void main(String[] args) {        Box<String> s=new Box<String>("http://blog.csdn.net/unix21");        Box<Integer> i=new Box<Integer>(123);        System.out.println("s class:" + s.getClass());        System.out.println("i class:" + i.getClass());        System.out.println(s.getClass() == i.getClass());        getData(Box.class);    }        public static void getData(Class<?> clz){        try {        System.out.println(clz);        System.out.println("clz.hashCode():" + clz.hashCode());        Object o=clz.newInstance();        o.hashCode();        System.out.println("o.hashCode():" + o.hashCode());        }         catch (Exception e) {          System.out.println(e);      }      }}


((Box)clz).getT();会报错:

不能将 "class java.lang.Class (no class loader)" 的实例强制转换为 "class test.Box (loaded by instance of sun.misc.Launcher$AppClassLoader(id=144))" 的实例

说明还没有class loader

((Box)o).getT();就已经实例化了。


3.Object类型

定义的所有类默认都是子类,所有的类都是以标准类Object为基础,Object类型的变量可以存储指向任意类类型对象的索引。

当要为一个方法来处理未知类型的对象时,这很有用。

//存储的地方        HashMap<String , Object> map = new HashMap<String , Object>();        User u1=new User();        u1.setId(1);        u1.setName("ww1");        //Object可以塞任意类型        map.put("user",u1);        User u=(User)map.get("user");        response.getWriter().println("Hello Servlet >>>"+u.getName());        String clazz ="com.w1.User"; //bean.getAttributeValue("class");        try {            //反射        Object o = Class.forName(clazz).newInstance();        map.put("user2",o);            User u2=(User)map.get("user2");            u2.setName("ww223");            response.getWriter().println("Hello Servlet >>>"+u2.getName());        } catch (Exception e) {            e.printStackTrace();        }


4.类名.class, class.forName(), getClass()区别

1:Class cl=A.class;  
JVM将使用类A的类装载器, 将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象。
2:Class cl=对象引用o.getClass();
返回引用o运行时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象 。
3:Class.forName("类名");
.装入类A,并做类的初始化
.getClass()是动态的,其余是静态的。
.class和class.forName()只能返回类内field的默认值,getClass可以返回当前对象中field的最新值
Class.forName() 返回的是一个类,.newInstance() 后才创建一个对象,Class.forName()的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的。

public class Person {    private String name = "Alfira";    public void getName() {        System.out.println(name);    }    public void setName(String name, int a) {        this.name = name + a;    }}

    private static void show(String name) {        try {            // JVM将使用类A的类装载器,将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作            Class classtype3 = Person.class;            // 获得classtype中的方法            Method getMethod3 = classtype3.getMethod("getName", new Class[] {});            Class[] parameterTypes3 = { String.class, int.class };            Method setMethod3 = classtype3.getMethod("setName", parameterTypes3);            // 实例化对象,因为这一句才会输出“静态初始化”以及“初始化”            Object obj3 = classtype3.newInstance();            // 通过实例化后的对象调用方法            getMethod3.invoke(obj3); // 获取默认值            setMethod3.invoke(obj3, "Setting new ", 3); // 设置            getMethod3.invoke(obj3); // 获取最新            System.out.println("----------------");            // 返回运行时真正所指的对象            Person p = new Person();            Class classtype = p.getClass();// Class.forName(name);            // 获得classtype中的方法            Method getMethod = classtype.getMethod("getName", new Class[] {});            Class[] parameterTypes = { String.class, int.class };            Method setMethod = classtype.getMethod("setName", parameterTypes);            getMethod.invoke(p);// 获取默认值            setMethod.invoke(p, "Setting new ", 1); // 设置            getMethod.invoke(p);// 获取最新            System.out.println("----------------");            // 装入类,并做类的初始化            Class classtype2 = Class.forName(name);            // 获得classtype中的方法            Method getMethod2 = classtype2.getMethod("getName", new Class[] {});            Class[] parameterTypes2 = { String.class, int.class };            Method setMethod2 = classtype2.getMethod("setName", parameterTypes2);            // 实例化对象            Object obj2 = classtype2.newInstance();            // 通过实例化后的对象调用方法            getMethod2.invoke(obj2); // 获取默认值            setMethod2.invoke(obj2, "Setting new ", 2); // 设置            getMethod2.invoke(obj2); // 获取最新            System.out.println("----------------");        } catch (Exception e) {            System.out.println(e);        }    }

调用

show("com.Person");

参考此文:http://www.cnblogs.com/feiyun126/archive/2013/08/01/3229492.html

http://blog.163.com/granite8@126/blog/static/853746082008610102657141/


5.动态代理和cglib

public class SayHello {    public void say(){    System.out.println("hello everyone");    }}

import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxy implements MethodInterceptor {    private Enhancer enhancer = new Enhancer();    public Object getProxy(Class clazz) {        //设置需要创建子类的类        enhancer.setSuperclass(clazz);        enhancer.setCallback(this);        //通过字节码技术动态创建子类实例        return enhancer.create();    }        //实现MethodInterceptor接口方法    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {        System.out.println("前置代理");        //通过代理类调用父类中的方法        Object result = proxy.invokeSuper(obj, args);        System.out.println("后置代理");        return result;    }}


调用

 CglibProxy proxy = new CglibProxy();            //通过生成子类的方式创建代理类            SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);            proxyImp.say();


CGLib动态代理原理及实现

Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)[转]

cglib动态代理介绍(一)


6.模仿Spring实现

需要说这个作者写到这一系列文章非常好【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)

代码:http://download.csdn.net/detail/jiuqiyuliang/8483981

 这篇博文的目标是不仅形似Spring的IoC,而且要神似Spring的IoC,将对象的依赖关系进一步封装。

完整的项目结构



Dao接口和实现

public interface Dao {public void daoMethod();}
public class Dao4MySqlImpl implements Dao {public void daoMethod(){System.out.println("Dao4MySqlImpl.daoMethod()");}}
public class Dao4OracleImpl implements Dao {public void daoMethod(){System.out.println("Dao4OracleImpl.daoMethod()");}}

Service接口和实现
public interface Service {public void serviceMethod();}
public class ServiceImpl implements Service {private Dao dao;  //依赖注入public void setDao(Dao dao) {this.dao= dao;}@Overridepublic void serviceMethod() {dao.daoMethod();}}

public interface BeanFactory {Object getBean(String beanName);}
import java.util.ArrayList;import java.util.List;public class BeanDefinition {private String id;private String className;private List<PropertyDefinition> propertys = new ArrayList<PropertyDefinition>();public BeanDefinition(String id, String className) {this.id = id;this.className = className;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public List<PropertyDefinition> getPropertys() {return propertys;}public void setPropertys(List<PropertyDefinition> propertys) {this.propertys = propertys;}}


核心容器

import org.jdom.Document;import org.jdom.Element;import org.jdom.input.SAXBuilder;import org.jdom.xpath.XPath;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 容器 * * @author liang * */public class ClassPathXmlApplicationContext implements BeanFactory {// 用于存放Beanprivate List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();// 用于存放Bean的实例private Map<String, Object> sigletons =new HashMap<String, Object>();public ClassPathXmlApplicationContext(String fileName) {this.readXML(fileName);this.instanceBeans();this.injectObject();}/** * 为bean对象的属性注入值 */private void injectObject() {for (BeanDefinition beanDefinition :beanDefines) {Object bean = sigletons.get(beanDefinition.getId());if(bean != null){try {// 通过Introspector取得bean的定义信息,之后再取得属性的描述信息,返回一个数组PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();for(PropertyDefinition propertyDefinition:beanDefinition.getPropertys()){for(PropertyDescriptor properdesc: ps){if(propertyDefinition.getName().equals(properdesc.getName())){// 获取属性的setter方法,privateMethod setter = properdesc.getWriteMethod();if(setter != null){Object value = sigletons.get(propertyDefinition.getRef());// 允许访问私有方法setter.setAccessible(true);// 把引用对象注入到属性setter.invoke(bean, value);}break;}}}} catch (Exception e) {e.printStackTrace();}}}}/** * 完成bean的实例化 */private void instanceBeans() {for(BeanDefinition beanDefinition : beanDefines){try {if(beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())){sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance() );}} catch (Exception e) {e.printStackTrace();}}}/** * 读取xml配置文件 */private void readXML(String fileName) {// 创建SAXBuilder对象SAXBuilder saxBuilder = new SAXBuilder();try {// 读取资源,获得document对象Document doc = saxBuilder.build(this.getClass().getClassLoader().getResourceAsStream(fileName));// 获取根元素Element rootEle = doc.getRootElement();// 从根元素获得所有的子元素,建立元素集合List listBean = XPath.selectNodes(rootEle, "/beans/bean");// 遍历根元素的子元素集合,扫描配置文件中的beanfor (int i = 0; i < listBean.size(); i++) {// 将根元素beans下的bean子元素作为一个新的子根元素Element elementBean = (Element) listBean.get(i);//获取id属性值String id = elementBean.getAttributeValue("id");//获取class属性值String clazz = elementBean.getAttributeValue("class");BeanDefinition beanDefine = new BeanDefinition(id,clazz);// 获取子根元素bean下的所有property子元素List listProperty = elementBean.getChildren("property");// 遍历子根元素的子元素集合(即遍历property元素)for (int j = 0; j < listProperty.size(); j++) {// 获取property元素Element elmentProperty = (Element)listProperty.get(j);// 获取name属性值String propertyName = elmentProperty.getAttributeValue("name");// 获取ref属性值String propertyref = elmentProperty.getAttributeValue("ref");PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName,propertyref);beanDefine.getPropertys().add(propertyDefinition);}// 将javabean添加到集合中beanDefines.add(beanDefine);}} catch (Exception e) {e.printStackTrace();}}/** * 获取bean实例 */@Overridepublic Object getBean(String beanName) {return this.sigletons.get(beanName);}}

public class PropertyDefinition {private String name;private String ref;public PropertyDefinition(String name, String ref) {this.name = name;this.ref = ref;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRef() {return ref;}public void setRef(String ref) {this.ref = ref;}}


applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans>  <bean id="dao" class="com.tgb.container.dao.impl.Dao4MySqlImpl" />  <bean id="service" class="com.tgb.container.service.impl.ServiceImpl">  <property name="dao" ref="dao"></property>  </bean></beans>

7.Smart Framework

Smart Framework:轻量级 Java Web 框架

Smart Framework是一个完整的类似Spring但是更轻量级的项目,学习框架的最佳材料之一。







0 1
原创粉丝点击