2016年1月20日 星期三

AOP3-Returning、Throwing、Around (Spring3.x 二十)

※AOP傳參數、Returning

※之前的before和after都沒有傳參數,現在傳個參數,還有回傳值的接收
使用B方法傳參數; D方法接收回傳值


※XML設定

IAOP.java和AOP.java

public interface IAOP {
    public void B(String s, Book b);
    public String D(String d);
}
    
@Named
public class AOP implements IAOP {
    @Override
    public void B(String s, Book b) {
        System.out.println("有參數B");
    }
    
    @Override
    public String D(String d) {
        System.out.println("有參數D");
        return d;
    }
}



Book.java

@Component("bo")
public class Book {
    private String bookName;
    private int bookPrice;
    // setter/getter...
}



BeforeAfter.java

@Named
public class BeforeAfter {
    public void beforeParam(Object o, Book b) {
        System.out.println("之前+參數,參數是:" + o + "和" + b.getBookName());
    }
    
    public void afterReturn(String s) {
        System.out.println("回傳值" + s);
    }
}



applicationContext.xml

<context:component-scan base-package="\" />
    <aop:config>
        <aop:aspect ref="beforeAfter">
    
        <aop:before method="beforeParam" pointcut="execution(public void aop.AOP.B(String, vo.Book)) and args(p1, p2)" arg-names="p1, p2" />
    
        <aop:after-returning method="afterReturn" pointcut="execution(public String aop.AOP.D(String))" returning="r1" arg-names="r1"/>
    </aop:aspect>
</aop:config>

※p1、p2, r1要對應好,Book用包.類,一般的可省略,如:String、int等


測試類
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
Book book = new Book();
book.setBookName("七龍珠");
book.setBookPrice(50);
    
IAOP aop = ctx.getBean("AOP", IAOP.class);
aop.B("ooo", book);
aop.D("ddd");
    
((ClassPathXmlApplicationContext) ctx).close();

※結果:
之前+參數,參數是:ooo和七龍珠
有參數B
有參數D
回傳值ddd


※Annotation設定

@Named
@Aspect
public class BeforeAfter {
    @Before(value="execution(public void aop.AOP.B(String, vo.Book)) and args(p1, p2)", argNames="p1, p2")
    public void beforeParam(Object o, Book b) {
        System.out.println("之前+參數,參數是:" + o + "和" + b.getBookName());
    }
    
    @AfterReturning(pointcut = "execution(public String aop.AOP.D(String))", returning = "r1", argNames = "r1")
    public void afterReturn(String s) {
        System.out.println("回傳值" + s);
    }
}



※Throwing 

如果有例外,可以設定抓例外的資訊



※XML設定 


IAOP.java和AOP.java

public interface IAOP {
    public void D(String d) throws ArithmeticException;
}
    
@Named
public class AOP implements IAOP {
    @Override
    public void D(String d) {
        System.out.println("有參數D");
        try {
            int a = 1 / 0;
        } catch (ArithmeticException e) {
            throw new ArithmeticException();
        }
    }
}



BeforeAfter.java

@Named
public class BeforeAfter {
    public void afterThrow(Exception e) {
        System.out.println("AOP截取例外:" + e);
    }
}



applicationContext.xml

<context:component-scan base-package="\" />
    
<aop:config>
    <aop:aspect ref="beforeAfter">
        <aop:after-throwing method="afterThrow" pointcut="execution(public void aop.AOP.D(String))" throwing="t1" arg-names="t1" />
    </aop:aspect>
</aop:config>

※和回傳值一樣,只不過屬性名稱變成throwing,要和arg-names對應


測試類

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
IAOP aop = ctx.getBean("AOP", IAOP.class);
try {
    aop.D("ddd");
} catch (ArithmeticException e) {}
    
((ClassPathXmlApplicationContext) ctx).close();

※結果:
有參數D
AOP截取例外:java.lang.ArithmeticException

※注意這個D方法沒有回傳值,但還是可以抓到喔!


※Annotation設定

@Named
@Aspect
public class BeforeAfter {
    @AfterThrowing(pointcut = "execution(public void aop.AOP.D(String))", throwing = "t1", argNames = "t1")
    public void afterThrow(Exception e) {
        System.out.println("AOP截取例外:" + e);
    }
}



※Around

IAOP.java和AOP.java

public interface IAOP {
    public String B(String s, Book b);
}
    
@Named
public class AOP implements IAOP {
    @Override
    public String B(String s, Book b) {
        System.out.println("有參數B");
        // try {
        // int a = 1 / 0;
        // } catch (Exception e) {
        // System.out.println("我錯了B");
        // }
        return "參數B回傳";
    }
}



Book.java

@Component("bo")
public class Book {
    private String bookName;
    private int bookPrice;
    // setter/getter...
}



BeforeAfter.java

// @Named
// @Aspect
public class BeforeAfter {
    // @Around("execution(public String aop.AOP.B(String, vo.Book))")
    // ProceedingJoinPoint可取得方法資訊
    public void around(ProceedingJoinPoint pjp) {
        System.out.println("around start" + Arrays.toString(pjp.getArgs()));
    
        try {
            // Object rtn = pjp.proceed();
            Object rtn = pjp.proceed(new Object[] { "hello String", new Book() });
            System.out.println("rtn=" + rtn);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}



<context:component-scan base-package="\" />
<!--     <aop:aspectj-autoproxy/> -->
    
<aop:config>
    <aop:aspect ref="beforeAfter">
        <aop:around method="around" pointcut="execution(public String aop.AOP.B(String, vo.Book))" />
    </aop:aspect>
</aop:config>



測試類

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
for (String s : ctx.getBeanDefinitionNames()) {
    System.out.println(s);
}
    
IAOP aop = ctx.getBean("AOP", IAOP.class);
Book book = new Book();
book.setBookName("七龍珠");
book.setBookPrice(50);
aop.B("ooo", book);
    
((ClassPathXmlApplicationContext) ctx).close();


※結果:
around start[ooo, vo.Book@3cc2931c]
有參數B
rtn=參數B回傳

※在BeforeAfter.java的proceed()是overloading,就這兩個方法,一開始會先像before一樣先執行,然後要繼續就要使用proceed(),沒加參數會自動幫我們執行,但要加型態和順序就要和B方法的參數一樣,否則會出錯

沒有留言:

張貼留言