Spring 框架 AOP 的總結

一:帝國之軍-AOP

1:案例分析

    ![事務案例](https://img-blog.csdn.net/2018040518063398?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

    上訴問題:在我們的業務層中每一個業務方法都的處理事務(頻繁的try-cache),在設計上存在兩個很嚴重問題:

    1):責任不分離,業務方法只需要關係如何完成業務功能,不需要去關心事務管理/日誌管理/權限管理等.

    2):代碼結構重複,在開發中不要重複代碼,重複就意味着維護成本增大.

    ![房租租賃案例](https://img-blog.csdn.net/20180405180731550?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

2.靜態代理

代理模式:客戶端直接使用的都是代理對象,不知道真實對象是誰,此時代理對象可以在客戶端和真是對象之間起到中介的作用

    1:代理對象完全包含真是對象,客戶端使用的都是代理對象的方法,和真是對象沒有直接關係;

    2:代理模式的職責:把不是真是對象該做的事情從真實對象上撇開--職責清晰;

靜態代理:在程序運行前就已經存在代理類的字節碼文件,代理對象和真是對象的關係在運行前就確定了.

    ![靜態代理](https://img-blog.csdn.net/20180405181345791?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

    ![靜態代理的優缺點](https://img-blog.csdn.net/20180405190832266?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
//靜態代理類
public class EmployeeServiceProxy implements IEmployeeService{

    private IEmployeeService target;//真是對象/委託對象

    private TransactionManager txManager;//事務管理器

    public void setTarget(IEmployeeService target) {
        this.target = target;
    }

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }

    public void save(Employee emp) {
        txManager.begin();
        try {
            target.save(emp);
            txManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            txManager.rollback();
        }
    }

    public void update(Employee emp) {
        txManager.begin();
        try {
            target.update(emp);
            txManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            txManager.rollback();
        }
    }
}

App

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {

    @Autowired
    //@Qualifier("employeeServiceProxy")
    //因爲代理類實現於接口,而接口還有一個imp類,xml配置文件的時候必須要標明,可以使用Qualifier標註,也可以跟下面一樣內部<bean>表示
    private IEmployeeService service;

    @Test
    public void testSave() throws Exception {
        System.out.println(service.getClass());//查看對象的真實類型
        service.save(new Employee());
    }

    @Test
    public void testUpdate() throws Exception {
        service.update(new Employee());
    }
}

App-Context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        " >

        <bean id="employeeDAO" class="cn.wolfcode.dao.imp.IEmployeeDAOImpl"/>

        <bean id="transactionManager" class="cn.wolfcode.tx.TransactionManager"/>

        <!-- 代理對象  -->
        <bean id="employeeServiceProxy" class="cn.wolfcode.proxy.EmployeeServiceProxy">
            <property name="txManager" ref="transactionManager"/>
            <property name="target" >
                <bean class="cn.wolfcode.service.IEmployeeServiceImpl">
                    <property name="dao" ref="employeeDAO"></property>
                </bean>
            </property>
        </bean>

</beans>

3.動態代理

動態代理:動態代理是在程勳運行期間有JVM通過反射等機制動態的生成的,所以不存在代理類的字節碼文件,代理

        對象和真實對象的關係是在程序運行時期才確定的.

如何實現動態代理:

    1):針對有接口:使用JDK動態代理

    2):針對無接口:使用CGLIB或Javassist組件

①JDK動態代理

domain

public class Employee {

}

dao

public interface IEmployeeDAO {

    void save(Employee emp);

    void update(Employee emp);
}

impl

public class IEmployeeDAOImpl implements IEmployeeDAO{

    public void save(Employee emp) {
        System.out.println("保存員工");
        System.out.println("保存成功");
    }

    public void update(Employee emp) {
        System.out.println("修改員工");
        throw new RuntimeException("故意錯誤");
    }
}

service

public interface IEmployeeService {

    void save(Employee emp);

    void update(Employee emp);
}

impl

public class IEmployeeServiceImpl implements IEmployeeService{

    private IEmployeeDAO dao;

    public void setDao(IEmployeeDAO dao) {
        this.dao = dao;
    }

    public void save(Employee emp) {
        dao.save(emp);
    }

    public void update(Employee emp) {
        dao.update(emp);
    }
}

tx

//模擬事務管理器:
public class TransactionManager {

    public void begin(){
        System.out.println("開啓事務");
    }

    public void commit(){
        System.out.println("提交事務");
    }

    public void rollback(){
        System.out.println("回滾事務");
    }
}
//事務的增強操作
@SuppressWarnings("all")
public class TransactionManagerAdvice implements InvocationHandler{

    private Object targer;//真實對象(對誰做增強)

    private TransactionManager txManager;//事務管理器(模擬)

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }

    public void setTarger(Object targer) {
        this.targer = targer;
    }

    //創建一個代理對象
    public <T> T getProxyObject(){
        return (T)Proxy.newProxyInstance(targer.getClass().getClassLoader(),//類加載器,一般跟上真實對象的類加載器S 
            targer.getClass().getInterfaces(),//真實對象實現的接口(JDK動態代理必須要求真是對象有接口)
            this);//如何做事務增強的對象
    }

    //如何爲真實對象的方法做增強的具體操作
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().startsWith("get")|| method.getName().startsWith("list")){
            return method.invoke(targer, args);//調用真實對象的方法
        }
        Object obj = null;
        txManager.begin();
        try {
            //-----------------------------------------------------
            obj = method.invoke(targer, args);//調用真實對象的方法
            //-----------------------------------------------------
            txManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            txManager.rollback();
        }
        return obj;
    }
}

App

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {

    @Autowired
    private TransactionManagerAdvice advice;

    //代理對象:com.sun.proxy.$Proxy19

    @Test
    public void testSave() throws Exception {
        //獲取代理對象
        IEmployeeService proxy = advice.getProxyObject();
        proxy.save(new Employee());
    }

    @Test
    public void testUpdate() throws Exception {
        //獲取代理對象
        IEmployeeService proxy = advice.getProxyObject();
        proxy.update(new Employee());
    }
}

App-Context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        " >

        <bean id="employeeDAO" class="cn.wolfcode.dao.imp.IEmployeeDAOImpl"/>

        <bean id="transactionManager" class="cn.wolfcode.tx.TransactionManager"/>

        <bean id="employeeService" class="cn.wolfcode.service.impl.IEmployeeServiceImpl">
            <property name="dao" ref="employeeDAO"></property>
        </bean>

        <!-- 代理對象  -->

        <!-- 配置一個事務增強的類 -->
        <bean id="transactionManagerAdvice" class="cn.wolfcode.tx.TransactionManagerAdvice">
            <property name="targer" ref="employeeService"></property>
            <property name="txManager" ref="transactionManager" />
        </bean> 
</beans>

②:CGLIB動態代理

domain

public class Employee {

}

dao

public interface IEmployeeDAO {

    void save(Employee emp);

    void update(Employee emp);
}

impl

public class IEmployeeDAOImpl implements IEmployeeDAO{

    public void save(Employee emp) {
        System.out.println("保存員工");
        System.out.println("保存成功");
    }

    public void update(Employee emp) {
        System.out.println("修改員工");
        throw new RuntimeException("故意錯誤");
    }
}

service.impl

public class EmployeeServiceImpl{

    private IEmployeeDAO dao;

    public void setDao(IEmployeeDAO dao) {
        this.dao = dao;
    }

    public void save(Employee emp) {
        dao.save(emp);
    }

    public void update(Employee emp) {
        dao.update(emp);
    }
}

tx

public class TransactionManager {

    public void begin(){
        System.out.println("開啓事務");
    }

    public void commit(){
        System.out.println("提交事務");
    }

    public void rollback(){
        System.out.println("回滾事務");
    }
}
@SuppressWarnings("all")
public class TransactionManagerAdvice implements org.springframework.cglib.proxy.InvocationHandler{

    private Object target;//真實對象(對誰做增強)

    private TransactionManager tx;//事務管理器(模擬)

    public void setTarget(Object target) {
        this.target = target;
    }

    public void setTx(TransactionManager tx) {
        this.tx = tx;
    }

    //創建一個代理對象
    public <T> T getProxyObject(){
        Enhancer enhencer = new Enhancer();
        enhencer.setSuperclass(target.getClass());//將繼承與哪一個類,去做增強
        enhencer.setCallback(this);//創建增強的對象
        return (T) enhencer.create();//創建代理對象
    }

    //如何爲真實對象的方法做增強的具體操作
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object obj = null;
        tx.begin();
        try {
            obj = method.invoke(target, args);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }
        return obj;
    }
}

App

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {

    @Autowired
    private TransactionManagerAdvice advice;

    //代理對象:com.sun.proxy.$Proxy19
    //CGLIB代理對象:class cn.wolfcode.service.impl.IEmployeeServiceImpl$$EnhancerByCGLIB$$8db50f30

    @Test
    public void testSave() throws Exception {
        EmployeeServiceImpl proxy = advice.getProxyObject();
        proxy.save(new Employee());
    }

    @Test
    public void testUpdate() throws Exception {
        EmployeeServiceImpl proxy = advice.getProxyObject();
        proxy.update(new Employee());
    }
}

App-Context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        " >

        <bean id="employeeDAO" class="cn.wolfcode.dao.imp.IEmployeeDAOImpl"/>

        <bean id="employeeService" class="cn.wolfcode.service.impl.EmployeeServiceImpl">
            <property name="dao" ref="employeeDAO"></property>
        </bean>

        <bean id="transactionManager" class="cn.wolfcode.tx.TransactionManager"></bean>

        <!-- 代理對象  -->
        <!-- 配置一個事務增強的類 -->
        <bean id="transactionManagerAdvice" class="cn.wolfcode.tx.TransactionManagerAdvice">
            <property name="target" ref="employeeService"></property>
            <property name="tx" ref="transactionManager"></property>
        </bean>

</beans>

③:攔截器的原理和日誌記錄

攔截器跟Filter過濾器很相似:

Filter就是對請求和響應做攔截.

Filter:         WEB領域的概念,只能針對請求和響應做增強,離不開servlet-api.jar

Integerceptor:  整個Java領域的概念,不僅可以運用到service層,還可以用到Web層.

domain

public class Employee {

}

dao

public interface IEmployeeDAO {

    void save(Employee emp);

    void update(Employee emp);
}

imp

public class IEmployeeDAOImpl implements IEmployeeDAO{

    public void save(Employee emp) {
        System.out.println("保存員工");
        System.out.println("保存成功");
    }

    public void update(Employee emp) {
        System.out.println("修改員工");
        throw new RuntimeException("故意錯誤");
    }
}

service

public class IEmployeeServiceImpl{

    private IEmployeeDAO dao;

    public void setDao(IEmployeeDAO dao) {
        this.dao = dao;
    }

    public void save(Employee emp) {
        dao.save(emp);
    }

    public void update(Employee emp) {
        dao.update(emp);
    }
}

log

public class LogUtil {

    public void writeLog(String className,String methodName){
        System.out.println(new Date().toLocaleString()+"調用了"+className+"類中的"+methodName+"方法");
    }
}
//日誌增強
public class LogAdvice implements org.springframework.cglib.proxy.MethodInterceptor{

    private Object target;//真實對象
    private LogUtil logUtil;

    public void setTarget(Object target) {
        this.target = target;
    }

    public void setLogUtil(LogUtil logUtil) {
        this.logUtil = logUtil;
    }

    //創建代理對象
    public <T> T getProxyObject(){
        /*Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return (T) enhancer.create();*/
        return (T) Enhancer.create(target.getClass(),this);
    } 

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        logUtil.writeLog(method.getDeclaringClass().getName(),method.getName());
        Object ret = method.invoke(target,args);//調用真實對象的方法
        return ret;
    }
}

App

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {

    @Autowired
    private LogAdvice advice;

    //代理對象:com.sun.proxy.$Proxy19
    //CGLIB代理對象:class cn.wolfcode.service.impl.IEmployeeServiceImpl$$EnhancerByCGLIB$$8db50f30
    @Test
    public void testSave() throws Exception {
        IEmployeeServiceImpl proxy = advice.getProxyObject();
        proxy.save(new Employee());
    }

    @Test
    public void testUpdate() throws Exception {
        IEmployeeServiceImpl proxy = advice.getProxyObject();
        proxy.update(new Employee());
    }
}

App-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        " >

        <bean id="employeeDAO" class="cn.wolfcode.dao.imp.IEmployeeDAOImpl"/>

        <bean id="logUtil" class="cn.wolfcode.log.LogUtil"/>

        <bean id="employeeService" class="cn.wolfcode.service.impl.IEmployeeServiceImpl">
            <property name="dao" ref="employeeDAO"></property>
        </bean>

        <!-- 代理對象  -->

        <!-- 配置一個事務增強的類 -->
        <bean id="logAdvice" class="cn.wolfcode.log.LogAdvice">
            <property name="target" ref="employeeService"></property>
            <property name="logUtil" ref="logUtil" />
        </bean> 
</beans>

4.代理總結

JDK動態代理總結:

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

    2:要使用JDK動態代理,委託必須要定義接口.

    3:JDK動態代理將會攔截所有public的方法(因爲只能調用接口中定義的方法),這樣即使在接口中定義了方法,不用修改代碼也會被攔截.

    4:動態代理的最小單位是類(所有類中的方法都會被處理),如果只想攔截一部分方法,可以在invoke方法中對要執行的方法名進行判斷.
CGLIB代理總結:

    1:CGLIB可以生成委託類的子類,並重寫父類非final修飾的方法.

    2:要求類不能是final,要攔截的方法要是非final,非static, 非private的.

    3:動態代理的最小單位是類(所有類中的方法都會被處理).
關於性能:

    JDK動態代理是基於實現接口的,CGLIB和Javassit是基於繼承委託類的.

    從性能上考慮: Javassit > CGLIB > JDK

    Struts2的攔截器和Hibemate延遲加載對象,採用的是Javassit的方式.

    對接口創建代理優於對類創建代理,因爲會產生更加鬆耦合的系統,也更符合面向接口編程規範.

    若委託對象實現了接口,優先選用JDK動態代理.

    若委託對象沒有實現任何接口,使用Javassit和CGLIB動態代理.

5.AOP思想

1.AOP思想和重要術語

AOP(Aspect oritention Programming):

    把一個個的橫切關注點放到某個模塊中去,稱之爲切面.那麼每一個的切面都能影響業務的某一種功能,切面的目的就是功能增強,

    如日誌切面就是一個橫切關注點,應用中許多方法需要做日誌記錄,只需要插入日誌的切面即可.
    Joinpoint: 連接點,被攔截到需要被增強的方法        WHERE  去哪裏做增強操作

    Pointcut: 切入點,需要爲哪些包中的哪些類中的哪些方法.Joinpoint的集合.  WHERE:去哪些地方做增強.

    Advice: 增強(通知),當攔截到Joinpoint之後,在方法執行的某一個時機(when),做怎麼樣的增強操作(what). 

    Aspect: 切面 Pointcut + Advice 去哪些地方+在什麼時候,做說明增強

    Target: 目標對象,被代理的目標對象

    Weaving: 織入,把 Advice 加到 Target 上之後,創建出Proxy對象的過程.

    Proxy: 一個類被AOP織入增強後,產生的代理類.
方法執行的時機:

            前置增強,  後置增強,  異常增強,  最終增強,  環繞增強

①:Pointcut表達式

AOP的規範本應該由SUN公司提出,但是被AOP聯盟捷足先登,AOP聯盟制定AOP規範,首先就要解決一個問題,怎麼表示切入點,也就是在哪些方法上增強(where).

AspectJ是一個面向切面的框架,Aspect切入點語法如下(表示在哪些包下的哪些類的哪些方法上做切入增強):

    翻譯成中文:execution(<修飾符>? <返回類型> <聲明類型>? <方法名>(<參數>) <異常>?)

    舉例   :public static Class java.Class.forName(String className)throws ClassNotFoundException

    通配符:

    *   :匹配任何部分,只能表示一個單詞

    ..  :可用於全限定名中和方法參數中,分別表示子包和0到N個參數

2.AOP開發

①:依賴

依賴的jar:

        spring-aop-版本.RELEASE.jar

        com.springsource.org-aopalliance-1.0.0.jar  Spring5以後不需要拷貝,納入了aop包中

        com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

②:AOP各種增強

before:前置增強         被增強方法執行之前執行         權限控制日誌記錄等

after-returning:後置增強  正常執行完畢後執行           提交事務/統計分析數據結果等

after-throwing:異常增強   被增強方法出現異常時執行      回滾事務/記錄日誌的日常信息

after:最終增強        無論是否有異常,最終都要執行的增強操作   釋放資源等

around:環繞增強      可以自定義在被增強方法的什麼時機執行(返回一個Object,參數ProceedingJoinPoint) 緩存,性能日誌,權限,事務管理
獲取被增強方法的信息,並可以傳遞給增強方法:

    Spring AOP:  Joinpoint類  連接點, 訪問被增強方法的真是對象,代理對象,方法參數等等

                  可以做前置,後置,異常,最終增強方法的參數,第一個參數

    ProceedingJoinpoint:是Joinipoint的子類,只用於環繞增強,作爲一個參數,

                        還可以調用真實對象中被增強的方法:
如何獲取增強方法裏的異常信息, 增強方法裏的參數JoinPoint,以及如何在環繞增強裏面調用真實方法?
//模擬事務管理器:
public class TransactionManager {

    public void begin(JoinPoint po){
        System.out.println("代理對象: "+po.getThis().getClass());
        System.out.println("目標對象: "+po.getTarget().getClass());
        System.out.println("被增強方法參數: "+Arrays.toString(po.getArgs()));
        System.out.println("當前連接點簽名: "+po.getSignature());
        System.out.println("當前連接點類型: "+po.getKind());
        System.out.println("開啓事務");
    }

    public void commit(JoinPoint po){
        System.out.println("提交事務");
    }

    public void rollback(JoinPoint po,Throwable tx){
        System.out.println("回滾事務"+"  方法的錯誤信息: "+tx.getMessage());
    }

    public void after(JoinPoint po){
        System.out.println("釋放資源");
    }

    public Object aroundMethod(ProceedingJoinPoint po){
        Object ret = null;
        System.out.println("開啓事務");
        try {
            ret = po.proceed();//調用真實對象的方法,取的一個返回值,查詢有返回值
            System.out.println("提交事務");
        } catch (Throwable e) {
            System.out.println("回滾事務   錯誤信息:"+e.getMessage());
        } finally {
            System.out.println("釋放資源");
        }
        return ret;
    }
}
  <!-- 1:what,做說明增強 -->
        <bean id="txManager" class="cn.wolfcode.tx.TransactionManager" />
        <aop:config proxy-target-class="false">
            <aop:aspect ref="txManager">  <!-- 關聯what -->

                <!-- 2:where:在哪些語句中的哪些類中的哪些方法上做增強 -->
                <aop:pointcut id="txPoint" expression="execution( * cn.wolfcode.service.*Service.*(..))"/>

                <!-- 3:when:在方法執行的什麼時機做增強 -->
                <aop:before method="begin" pointcut-ref="txPoint"/>       
                <aop:after-returning method="commit" pointcut-ref="txPoint"/>
                <aop:after-throwing method="rollback" pointcut-ref="txPoint" throwing="tx"/>
                <aop:after method="after" pointcut-ref="txPoint"/>

                <!-- <aop:around method="aroundMethod" pointcut-ref="txPoint"/> -->
            </aop:aspect>
        </aop:config>

③:使用註解開發AOP

@Component
@Aspect    //配置一個切面
public class TransactionManager {

    @Pointcut("execution( * cn.wolfcode.service.impl.*.*(..))")
    public void txPoint(){
    }

    //@Before("txPoint()")
    public void begin(JoinPoint po){
        System.out.println("開啓事務");
    }

    //@AfterReturning("txPoint()")
    public void commit(JoinPoint po){
        System.out.println("提交事務");
    }

    //@AfterThrowing(value="txPoint()",throwing="tx")
    public void rollback(JoinPoint po,Throwable tx){
        System.out.println("回滾事務"+"  方法的錯誤信息: "+tx.getMessage());
    }

    //@After("txPoint()")
    public void after(JoinPoint po){
        System.out.println("釋放資源");
    }

    @Around("txPoint()")
    public Object aroundMethod(ProceedingJoinPoint po){
        Object ret = null;
        System.out.println("開啓事務");
        try {
            ret = po.proceed();//調用真實對象的方法,取的一個返回值,查詢有返回值
            System.out.println("提交事務");
        } catch (Throwable e) {
            System.out.println("回滾事務   錯誤信息:"+e.getMessage());
        } finally {
            System.out.println("釋放資源");
        }
        return ret;
    }
}
     <!-- DI註解解析器 -->
       <context:annotation-config/>
       <!-- IoC註解解析器-->
       <context:component-scan base-package="cn.wolfcode"/>
       <!-- AOP註解解析器 -->
       <!-- 當有接口的時候自動使用JDK代理, 沒有接口的時候自動使用CGLIB代理   AOP的本質是動態代理 -->
       <aop:aspectj-autoproxy proxy-target-class="false"/>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章