支撐Spring的基礎技術:反射,動態代理,cglib等
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();
}
}
物件的初始化順序:
首先執行父類靜態的內容,父類靜態的內容執行完畢後,接著去執行子類的靜態的內容,當子類的靜態內容執行完畢之後,再去看父類有沒有非靜態程式碼塊,
如果有就執行父類的非靜態程式碼塊,父類的非靜態程式碼塊執行完畢,接著執行父類的構造方法;父類的構造方法執行完畢之後,它接著去看子類有沒有非靜態程式碼塊,如果有就執行子類的非靜態程式碼塊。
子類的非靜態程式碼塊執行完畢再去執行子類的構造方法。
靜態程式碼塊的應用
需要一個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); } }
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());
}
}
參考:
再來看看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
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();
6.模仿Spring實現
這篇博文的目標是不僅形似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;
}
@Override
public 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 {
// 用於存放Bean
private 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方法,private
Method 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");
// 遍歷根元素的子元素集合,掃描配置檔案中的bean
for (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例項
*/
@Override
public 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是一個完整的類似Spring但是更輕量級的專案,學習框架的最佳材料之一。