1. 程式人生 > >Spring學習筆記(四)

Spring學習筆記(四)

array contain ets loader html 新的 -c spring學習 llb

本教程對應視頻課程:http://edu.51cto.com/course/14731.html

1、自動裝配

1.1、Spring標簽

Autowired標簽的作用

1、通過autowired標簽可以讓spring自動的把屬性需要的對象從容器中找出來,並註入到對象

2、autowired標簽可以放在字段或者setter方法上面

3、使用autowired標簽可以註入一些spring內置的重要對象,比如BeanFactory,ApplicationContext;

4、默認情況下,@Autowired標簽必須要能找到對應的對象,否則報錯;通過required=false來避免這個問題@Autowired(required=false)

5、第三方程序:spring3.0之前,需要手動配置@Autowired解析程序:spring就會自動的加入針對@Autowired標簽的解析程序<context:annotation-config />

6、@Autowired找bean的方式:

? ①首先按照依賴對象的類型找;如果找到,就是用setter或者字段直接註入

? ②如果在Spring上下文中找到多個匹配的類型,再按照名字去找;如果沒有匹配,報錯

? ③可以通過使用@Qualifier("other")標簽來規定依賴對象按照bean的id+類型去找

1.2、J2EE標簽

@Resource標簽:

1.Resource標簽是JavaEE規範的標簽、

2、Resource標簽也可以作用於字段或者setter方法

3、也可以使用@Resource標簽註入一些spring內置的重要對象,比如BeanFactory.ApplicationContext

4、Resource必須要求有匹配的對象

5、Resource標簽找bean的方式

? ①首先按照名字去找,如果找到,就使用setter或者字段註入

? ②如果按照名字找不到,再按照類型去找,但如果找到多個匹配類型則會報錯

? ③可以直接使用name屬性指定bean的名稱;但是,如果指定的name,就只能按照name去找,如果找不到,就不會再按照類型去找;

1.3、使用註解來化解配置

1、使用標簽來完成IoC,就必須有IoC標簽的解析器

? 使用context:component-scan來掃描spring需要管理的bean

? base-package就告訴spring去哪些包及其子包裏去掃描bean,如果有多個包需要被掃描;只需要用逗號隔開多個包即可

? <context:component-scan base-package="cn.org.kingdom.service,cn.org.kingdom.dao" />

2、標註Bean的註解:@Component

默認情況,直接使用類的名字(首字母小寫作為bean的名字), 如果要修改bean的名稱;直接使用value屬性來重新定義bean的名稱

@Component("otherbean")

public class OtherBean {}

3、使用@Component的限制:

①不能運用到靜態工廠方法和實例工廠方法,但是可以使用到FactoryBean;

②對於沒有源代碼的類(框架內部的預定義類),只能用XML配置;

4、bean組件分類

@Service用於標註業務層組件

@Controller用於標註控制層組件(如struts中的action)

@Repository用於標註數據訪問組件,即DAO組件

@Component泛指組件,當組件不好歸類的時候,我們可以使用這個註解進行標註。

5、指定bean的作用域:@Scope("prototype")

6、初始化和銷毀方法

<bean init-method="init" />

@PostConstruct

public void init() {}

<bean destory-method="destory" />

@PreDestroy

public void destory() {}

1、動態代理

1.1、靜態代理回顧

1.1.1、模型圖

技術分享圖片

1.1.2、代碼實現

package cn.org.kingdom.proxy;
interface Subject{
    public void getMoney();
}
class RealSubject implements Subject{
    @Override
    public void getMoney() {
        System.out.println("求求你,能不能還我錢");
    }
}
class Proxy implements Subject{
    private Subject subject;
    public Subject getSubject() {
        return subject;
    }
    public void setSubject(Subject subject) {
        this.subject = subject;
    }
    public void preGetMoney(){
        System.out.println("帶上大砍刀");
    }
    @Override
    public void getMoney() {
        preGetMoney();
        subject.getMoney();
        afterGetMoney();
    }
    public void afterGetMoney(){
        System.out.println("賠償精神損失費,拿去傭金");
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        RealSubject real = new RealSubject() ; 
        Proxy p = new Proxy();
        p.setSubject(real);
        p.getMoney();
    }
}

1.1.3、靜態代理

1、代理對象完全包含真實對象,客戶端使用的都是代理對象上面的方法,和真實對象無關;

2、靜態代理能夠處理把不是真實對象該做的事情從真實對象上面撇開;

3、靜態代理帶來的問題:需要為每一個真實對象都得創建一個代理對象,導致類會急劇增加

1.2、動態代理

1.2.1、jdk的動態代理

/**
    ClassLoader loader:類加載器
    Class<?>[] interfaces:要實現的接口
    InvocationHandler h:調用處理器
    return :代理對象
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h){}
/**
    proxy:生成的代理對象
    method:當前調用的真實方法
    args: 當前調用方法的實參
    return : 真實方法的返回結果
*/
public Object invoke(Object proxy, Method method, Object[] args) {}    

參考代碼

package cn.org.kingdom.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.org.kingdom.ts.Transation;
public class MyinvocationHanlder implements InvocationHandler {
    //真實角色
    private Object obj ;  //obj必須實現接口(jdk原生動態代理)
    //ts附加功能對象
    private Transation ts ; 
    public MyinvocationHanlder() {
        super();
    }
    public MyinvocationHanlder(Object obj, Transation ts) {
        super();
        this.obj = obj;
        this.ts = ts;
    }
    public Object getObj() {
        return obj;
    }
    public void setObj(Object obj) {
        this.obj = obj;
    }
    public Transation getTs() {
        return ts;
    }
    public void setTs(Transation ts) {
        this.ts = ts;
    }
    public Object getProxy(){
        return 
                Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object value = null ; 
        if(obj.getClass().getName().endsWith("ServiceImpl")){
            if("add".equals(method.getName())||"insert".equals(method.getName())) {
                //aop要植入的操作
                try{
                    ts.begin();
                    value= method.invoke(obj, args);
                    int c= 10/0;
                    ts.commit();
                }catch(Exception e)  {
                    ts.rollback();
                }
                return value;
            }else{
                method.invoke(obj, args);
            }
        }   
        return null;
    }
}

JDK動態代理

①代理的對象必須要實現一個接口;

②需要為每個對象創建代理對象;

③動態代理的最小單位是類(所有類中的方法都會被處理);

JDK動態代理總結

①JAVA動態代理是使用java.lang.reflect包中的Proxy類與InvocationHandler接口這兩個來完成的。

②要使用JDK動態代理,必須要定義接口。

③JDK動態代理將會攔截所有pubic的方法(因為只能調用接口中定義的方法),這樣即使在接口中增加了新的方法,不用修改代碼也會被攔截。

④如果只想攔截一部分方法,可以在invoke方法中對要執行的方法名進行判斷

1.2.2、CGLIB動態代理

若一個類,沒有接口如何代理 ?

javassist.jar:Struts2的代理實現方案.

cglib.jar:Spring的代理實現方案

java類實現

public class TransactionCallback implements org.springframework.cglib.proxy.InvocationHandler {
    private Object target;//真實對象
    private TransactionManager txManager;
    //不需要事務的方法
    private String[] methodNames = { "update", "get" };
    public TransactionCallback(Object target, TransactionManager txManager) {
        this.target = target;
        this.txManager = txManager;
    }
    //創建代理對象
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(this.getClass().getClassLoader());
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    public Object invoke(Object proxy, Method method, Object[] args){
        Object ret = null;
        if(Arrays.asList(methodNames).contains(method.getName())){
            method.invoke(target, args);
            return null;
        }
        txManager.beginTransaction();
        try {
            method.invoke(target, args);
            txManager.commint();
        } catch (Exception e) {
            txManager.rollback();
        }
        return ret;
    }
}

總結:

CGLIB代理總結:

①CGLIB可以生成目標類的子類,並重寫父類非final修飾符的方法。

②要求類不能是final的,要攔截的方法要是非final、非static、非private的。

③動態代理的最小單位是類(所有類中的方法都會被處理);

代理總結:

Spring中:

1、若目標對象實現了若幹接口,spring就會使用JDK動態代理。

2、若目標對象沒有實現任何接口,spring就使用CGLIB庫生成目標對象的子類。對接口創建代理優於對類創建代理,因為會產生更加松耦合的系統。

Spring學習筆記(四)