一. 應用開發(fā)指導和規(guī)則
想通過提供一種在編譯時強制執(zhí)行的策略,來控制在應用程序中允許哪些程序構造。可使用Border Controller(邊界控制器)面向方面設計模式聲明代碼內的一組區(qū)域。當依據策略模式在方面中為項目聲明任何頂級規(guī)則時,重用這些區(qū)域。可以擴展項目的頂級策略,為應用程序的特定區(qū)域特殊化它們。
示例中BorderControllerAspect聲明了4個區(qū)域:withinTestingRegion()區(qū)域納入了存放測試代碼的包,withinMyapp()指定了組成應用程序的包和子包,withinThirdParty()指定了可以使用第三方源代碼的任何區(qū)域,withinMyAppMainMethod()則方便地聲明了應用程序的main(..)方法的位置。
package com.aspectj;

public aspect BorderControllerAspect


{

/** *//**
* Specifies the testing region.
*/
public pointcut withinTestingRegion() : within(com.oreilly.aspectjcookbook.testing.+);

/** *//**
* Specifies My Applications region.
*/
public pointcut withinMyApp() : within(com.oreilly.aspectjcookbook.myapp.+);

/** *//**
* Specifies a third party source code region.
*/
public pointcut withinThirdParty() : within(com.oreilly.aspectjcookbook.thirdpartylibrary.+);

/** *//**
* Specifies the applications main method.
*/
public pointcut withinMyAppMainMethod() : withincode(public void com.oreilly.aspectjcookbook.myapp.MyClass.main(..));
}

示例中只顯示了可以在應用程序中定義的其中一些區(qū)域,其他良好的候選有:將發(fā)生特殊日志據記錄的區(qū)域;受延遲加載邏輯支配的區(qū)域;以及你發(fā)現(xiàn)體系結構的真實定界部分是有用的任何區(qū)域,他們使得更多的切入點定義可以重用,并在那些邊界內安全地工作。其思想是:如果這些邊界發(fā)生變化,則只需要更改Boarder Controller,使得應用程序其余切入點邏輯將立即獲得對其作用域的任何相關的改變。
Border Controller提供了一個有用的可重用切入點定義的庫,它被納入到策略面向方面設計模式中。
package com.aspectj;

public abstract aspect ProjectPolicyAspect


{
protected abstract pointcut allowedSystemOuts();
declare warning :
call(* *.println(..)) &&
!allowedSystemOuts() &&
!BorderControllerAspect.withinTestingRegion()
: "System.out usage detected. Suggest using logging?";
}
為應用程序區(qū)域的細節(jié)特殊化項目級策略
package com.aspectj;

public aspect MyAppPolicyAspect extends ProjectPolicyAspect


{

/** *//**
* Specifies regions within the application where system out
* messages are allowed.
*/
protected pointcut allowedSystemOuts() :
BorderControllerAspect.withinMyAppMainMethod() ||
BorderControllerAspect.withinThirdParty() ||
BorderControllerAspect.withinTestingRegion();
}
二.應用事務
package com.aspectj;

public abstract aspect TransactionAspect


{
protected abstract pointcut transactionalCall();
protected interface Transaction

{
public void commit();
public void rollback();
}
protected pointcut transactionBoundary() :
transactionalCall() && !cflowbelow(transactionalCall());
before() : transactionBoundary()

{
setupTransaction(thisJoinPoint.getArgs());
}
after() returning: transactionBoundary()

{
transaction.commit();
}
after() throwing: transactionBoundary()

{
transaction.rollback();
}
protected abstract void setupTransaction(Object[] args);
protected Transaction transaction;
}

TransactionAspect首先指定transactionCall()抽象切入點。特殊化的子方面使用這個切入點來指定將把目標應用程序內的方法視作事務性的。
transactionBounday()切入點然后依靠transactionCall()切入點來指定事務開始和結束的位置。cflowbelow()切入點用于忽略可能出現(xiàn)在事務壽命內的任何連接點。
TransactionAspect()一般需要存儲事務并與之交互,因此定義了Transaction接口。Transaction接口為子方面提供了一個基礎,用以實現(xiàn)他們自己的事務類。然后使用單個事務屬性來指定正被方面管理的當前事務。
最后,在事務生命周期內的不同時刻,將有三份通知處理事務屬性。before()通知調用setupTransaction(Object[])抽象方法,以便用合適的Transaction實現(xiàn)正確地初始化事務屬性。如果transactionCall()切入點所選的連接點未引發(fā)異常地返回,將會執(zhí)行after() returning通知;這是提交事務的良好時間。after() throwing通知用于連接點帶異常地返回的情況,因此需要回滾事務。
package com.aspectj;

public aspect TransferTransactionAspect extends TransactionAspect


{
protected pointcut transactionalCall() :
call(public void com.oreilly.aspectjcookbook.Bank.transfer(..));
private class TransferTransaction extends ThreadLocal implements Transaction

{
private Account from;
private Account to;
private float value;
public TransferTransaction(Account from, Account to, float value)

{
this.from = from;
this.to = to;
this.value = value;
}
public void commit()

{
System.out.println("Committing");
// Nothing to actually commit here, all the changes have been accepted ok
}
public void rollback()

{
System.out.println("Rolling back");
try

{
to.debit(value);
}
catch(InsufficientFundsException ife)

{
System.err.println("Could not complete rollback!");
ife.printStackTrace();
}
}
}
protected void setupTransaction(Object[] args)

{
this.transaction =
new TransferTransaction(
(Account) args[0],
(Account) args[1],
((Float)args[2]).floatValue());
}
}

三.應用資源池
package com.aspectj;

import java.util.WeakHashMap;

public abstract aspect ResourcePoolingAspect


{
public interface Resource

{
}
public interface ResourcePool

{
public void add(Resource resource);
public Resource remove();
}
protected class ResourcePoolsCollection

{
WeakHashMap pools = new WeakHashMap();
public void putResourcePool(ResourcePool pool, Class resourceClass)

{
pools.put(resourceClass, pool);
}
public ResourcePool getResourcePool(Class resourceClass)

{
return (ResourcePool) pools.get(resourceClass);
}
}
protected ResourcePoolsCollection resourcePools = new ResourcePoolsCollection();
public ResourcePoolingAspect()

{
initializeSpecificPool();
}
protected abstract void initializeSpecificPool();
private pointcut excludeAspects() : !within(ResourcePoolingAspect+);
public abstract pointcut catchResourceConstruction();
public abstract pointcut catchResourceDestruction(Resource resource);
Object around() : catchResourceConstruction() && excludeAspects()

{
ResourcePool resources =
resourcePools.getResourcePool(thisJoinPoint.getSignature().getDeclaringType());
return resources.remove();
}
Object around(Resource resource) : catchResourceDestruction(resource) && excludeAspects()

{
ResourcePool resources =
resourcePools.getResourcePool(thisJoinPoint.getSignature().getDeclaringType());
Object returnValue = resourceReturnedToPool(resource);
System.out.println("Resource added back into pool: " + resource);
resources.add(resource);
return returnValue;
}
protected abstract Object resourceReturnedToPool(Resource resource);
}

示例中定義了一個可重用的抽象方面,它將在最初不支持資源池的應用程序內提供一個資源池。聲明Resource和ResourcePool接口,以便可以對這些接口定義通用的資源池行為,并把它們與這些接口可能的實現(xiàn)方式隔離開。
可以跨所有聲明為子方面的資源池共享在抽象的ResourcePoolingAspect內聲明的行為。ResourcePoolCollection類為整個應用程序中的所有資源池提供了一個公共庫,使得通用代碼可以依據特定資源池說包含資源的類,來查尋該資源池。
package com.aspectj;

import java.util.List;
import java.util.ArrayList;

public aspect BusinessResourcePoolingAspect extends ResourcePoolingAspect


{
declare parents : BusinessResource implements Resource;

public pointcut catchResourceConstruction() : call(public BusinessResource.new());
public pointcut catchResourceDestruction(Resource resource) :
call(public void BusinessResource.close()) && target(resource);

private class BusinessResourcePool implements ResourcePool

{
private static final int RESOURCE_POOL_SIZE = 10;
List resources = new ArrayList();
public BusinessResourcePool()

{
for (int x = 0; x < RESOURCE_POOL_SIZE; x++)

{
this.add(new BusinessResource());
}
}
public synchronized void add(Resource resource)

{
resources.add(resource);
}
public synchronized Resource remove()

{
if (resources.size() == 0)

{
resources.add(new BusinessResource());
}
return (Resource) resources.remove(resources.size() - 1);
}
}
protected void initializeSpecificPool()

{
try

{
this.resourcePools.putResourcePool(new BusinessResourcePool(),
Class.forName("com.oreilly.aspectjcookbook.BusinessResource"));
}
catch (ClassNotFoundException cnfe)

{
System.err.println("Couldn't find resource class to pool");
}
}
protected Object resourceReturnedToPool(Resource resource)

{
// Do any resource specific tudying up if necessary
// None to do in this example
return null;
}
}

四.使用RMI透明地遠程訪問類
創(chuàng)建一個RMI服務器應用程序,它包含類的一個實例。如:
import java.rmi.RemoteException;
import java.rmi.server.*;

public class ThisOrThatServerImpl extends UnicastRemoteObject implements ThisOrThatServer


{
BusinessClass businessClass = new BusinessClass();
public ThisOrThatServerImpl() throws RemoteException

{
}
public void foo() throws RemoteException

{
this.businessClass.foo();
}
}
在客戶應用程序內創(chuàng)建一個方面,它用于截獲對遠程類的特定實例的調用,并把這些調用路由到相應的RMI服務器,如:

import java.rmi.*;

public aspect RemoteBusinessClassAspect


{
public pointcut callBusinessClassFooInMain() : call(public void BusinessClass.foo()) &&
withincode(public void MainApplication.main(String[]));
void around() : callBusinessClassFooInMain()

{
try

{
ThisOrThatServer rmtServer = (ThisOrThatServer) Naming.lookup("rmi://localhost/TTTServer");
rmtServer.foo();
}
catch (Exception e)

{
System.err.println("Problems occured when attempting " +
"to use remote object, default to local");
proceed();
}
}
}
五.應用安全策略
package com.aspectj;


public aspect SecureClassAAspect


{
private boolean authenticated;
public pointcut secureClassAMethods() :
call(* com.oreilly.aspectjcookbook.ClassA.*(..));
Object around() : secureClassAMethods()

{
if (authenticated)

{
return proceed();
}
else

{
LoginScreen loginScreen = new LoginScreen();
loginScreen.setVisible(true);
// Use the authentication procedure of your choice here
// In this simple example we are just going to check that
// it is the one person we know of
if ((loginScreen.getUsername().equals("Richard")) &&
(new String(loginScreen.getPassword()).equals("password")))

{
authenticated = true;
loginScreen.dispose();
return proceed();
}
loginScreen.dispose();
return null;
}
}
}
