Aspect Oriented Programming 面向切面編程。解耦是程序員編碼開(kāi)發(fā)過(guò)程中一直追求的。AOP也是為了解耦所誕生。
具體思想是:定義一個(gè)切面,在切面的縱向定義處理方法,處理完成之后,回到橫向業(yè)務(wù)流。
AOP 在Spring框架中被作為核心組成部分之一,的確Spring將AOP發(fā)揮到很強(qiáng)大的功能。最常見(jiàn)的就是事務(wù)控制。工作之余,對(duì)于使用的工具,不免需要了解其所以然。學(xué)習(xí)了一下,寫(xiě)了些程序幫助理解。
AOP 主要是利用代理模式的技術(shù)來(lái)實(shí)現(xiàn)的。
1、靜態(tài)代理:就是設(shè)計(jì)模式中的proxy模式
a、業(yè)務(wù)接口
/**
* 抽象主題角色:聲明了真實(shí)主題和代理主題的共同接口。
*
* @author yanbin
*
*/
public interface ITalk {
public void talk(String msg);
}
b、業(yè)務(wù)實(shí)現(xiàn)
/**
* 真實(shí)主題角色:定義真實(shí)的對(duì)象。
*
* @author yanbin
*
*/
public class PeopleTalk implements ITalk {
public String username;
public String age;
public PeopleTalk(String username, String age) {
this.username = username;
this.age = age;
}
public void talk(String msg) {
System.out.println(msg + "!你好,我是" + username + ",我年齡是" + age);
}
public String getName() {
return username;
}
public void setName(String name) {
this.username = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
c、代理對(duì)象
/**
* 代理主題角色:內(nèi)部包含對(duì)真實(shí)主題的引用,并且提供和真實(shí)主題角色相同的接口。
*
* @author yanbin
*
*/
public class TalkProxy implements ITalk {
private ITalk talker;
public TalkProxy(ITalk talker) {
// super();
this.talker = talker;
}
public void talk(String msg) {
talker.talk(msg);
}
public void talk(String msg, String singname) {
talker.talk(msg);
sing(singname);
}
private void sing(String singname) {
System.out.println("唱歌:" + singname);
}
}
d、測(cè)試類(lèi)
/**
* 代理測(cè)試類(lèi),使用代理
*
* @author yanbin
*
*/
public class ProxyPattern {
public static void main(String[] args) {
// 不需要執(zhí)行額外方法的。
ITalk people = new PeopleTalk("AOP", "18");
people.talk("No ProXY Test");
System.out.println("-----------------------------");
// 需要執(zhí)行額外方法的(切面)
TalkProxy talker = new TalkProxy(people);
talker.talk("ProXY Test", "代理");
}
}
從這段代碼可以看出來(lái),代理模式其實(shí)就是AOP的雛形。 上端代碼中talk(String msg, String singname)是一個(gè)切面。在代理類(lèi)中的sing(singname)方法是個(gè)后置處理方法。
這樣就實(shí)現(xiàn)了,其他的輔助方法和業(yè)務(wù)方法的解耦。業(yè)務(wù)不需要專(zhuān)門(mén)去調(diào)用,而是走到talk方法,順理成章的調(diào)用sing方法
再?gòu)倪@段代碼看:1、要實(shí)現(xiàn)代理方式,必須要定義接口。2、每個(gè)業(yè)務(wù)類(lèi),需要一個(gè)代理類(lèi)。
2、動(dòng)態(tài)代理:jdk1.5中提供,利用反射。實(shí)現(xiàn)InvocationHandler接口。
業(yè)務(wù)接口還是必須得,業(yè)務(wù)接口,業(yè)務(wù)類(lèi)同上。
a、代理類(lèi):
/**
* 動(dòng)態(tài)代理類(lèi)
*
* @author yanbin
*
*/
public class DynamicProxy implements InvocationHandler {
/** 需要代理的目標(biāo)類(lèi) */
private Object target;
/**
* 寫(xiě)法固定,aop專(zhuān)用:綁定委托對(duì)象并返回一個(gè)代理類(lèi)
*
* @param delegate
* @return
*/
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* @param Object
* target:指被代理的對(duì)象。
* @param Method
* method:要調(diào)用的方法
* @param Object
* [] args:方法調(diào)用時(shí)所需要的參數(shù)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 切面之前執(zhí)行
System.out.println("切面之前執(zhí)行");
// 執(zhí)行業(yè)務(wù)
result = method.invoke(target, args);
// 切面之后執(zhí)行
System.out.println("切面之后執(zhí)行");
return result;
}
}
b、測(cè)試類(lèi)
/**
* 測(cè)試類(lèi)
*
* @author yanbin
*
*/
public class Test {
public static void main(String[] args) {
// 綁定代理,這種方式會(huì)在所有的方法都加上切面方法
ITalk iTalk = (ITalk) new DynamicProxy().bind(new PeopleTalk());
iTalk.talk("業(yè)務(wù)說(shuō)明");
}
}
輸出結(jié)果會(huì)是:
切面之前執(zhí)行
people talk業(yè)務(wù)說(shuō)法
切面之后執(zhí)行
說(shuō)明只要在業(yè)務(wù)調(diào)用方法切面之前,是可以動(dòng)態(tài)的加入需要處理的方法。
從代碼來(lái)看,如果再建立一個(gè)業(yè)務(wù)模塊,也只需要一個(gè)代理類(lèi)。ITalk iTalk = (ITalk) new DynamicProxy().bind(new PeopleTalk()); 將業(yè)務(wù)接口和業(yè)務(wù)類(lèi)綁定到動(dòng)態(tài)代理類(lèi)。
但是這種方式:還是需要定義接口。
3、利用cglib
CGLIB是針對(duì)類(lèi)來(lái)實(shí)現(xiàn)代理的,他的原理是對(duì)指定的目標(biāo)類(lèi)生成一個(gè)子類(lèi),并覆蓋其中方法實(shí)現(xiàn)增強(qiáng)。采用的是繼承的方式。不細(xì)說(shuō),看使用
a、業(yè)務(wù)類(lèi)
/**
* 業(yè)務(wù)類(lèi)
*
* @author yanbin
*
*/
public class PeopleTalk {
public void talk(String msg) {
System.out.println("people talk" + msg);
}
}
b、cglib代理類(lèi)
/**
* 使用cglib動(dòng)態(tài)代理
*
* @author yanbin
*
*/
public class CglibProxy implements MethodInterceptor {
private Object target;
/**
* 創(chuàng)建代理對(duì)象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回調(diào)方法
enhancer.setCallback(this);
// 創(chuàng)建代理對(duì)象
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result = null;
System.out.println("事物開(kāi)始");
result = methodProxy.invokeSuper(proxy, args);
System.out.println("事物結(jié)束");
return result;
}
}
c.測(cè)試類(lèi)
/**
* 測(cè)試類(lèi)
*
* @author yanbin
*
*/
public class Test {
public static void main(String[] args) {
PeopleTalk peopleTalk = (PeopleTalk) new CglibProxy().getInstance(new PeopleTalk());
peopleTalk.talk("業(yè)務(wù)方法");
peopleTalk.spreak("業(yè)務(wù)方法");
}
}
最后輸出結(jié)果:
事物開(kāi)始
people talk業(yè)務(wù)方法
事物結(jié)束
事物開(kāi)始
spreak chinese業(yè)務(wù)方法
事物結(jié)束
由于篇幅有限,這篇主要對(duì)AOP的原理簡(jiǎn)單實(shí)現(xiàn)做了演示和闡述,有助自己理解。至于Spring的AOP實(shí)現(xiàn)上面無(wú)外乎其右,不過(guò)實(shí)現(xiàn)方面復(fù)雜的多。
原文出自:
http://www.cnblogs.com/yanbincn/archive/2012/06/01/2530377.html