Services
可以在AppModule类中追加如下方法:
public static SomeInterface build(){ return new SomeInterfaceImpl(); }
我们的方法可以使build,也可以是以build开头的方法,如buildSomething。
还有一种更为推荐的方式为使用
public static void bind(ServiceBinder binder){ binder.bind(SomeInterface.class, SomeInterfaceImpl.class); }
甚至,如果一个接口跟它的实现类在一个package下的话,并且实现类的名字为接口的名字+impl的话,可以省略掉后一个参数,如:
public static void bind(ServiceBinder binder){ binder.bind(SomeInterface.class); }
Service Id
每一个Service都有一个名字,默认的名字就是Service的class名称,如果修改的话,可以使用@ServiceId注解
@ServiceId("FileSystemIndexer") public static Indexer buildIndexer(@InjectService("FileSystem") FileSystem fileSystem) { . . . }
另外一种就是
public static Indexer buildFileSystemIndexer(@InjectService("FileSystem") FileSystem fileSystem) { . . . }
还有一种
@ServiceId("FileSystemIndexer") public class IndexerImpl implements Indexer { ... }
// Module.classbinder.bind(Indexer.
class
, IndexerImpl.
class
);
还有另外一种:
binder.bind(Indexer.class, IndexerImpl.class).withId("FileSystemIndexer");
HOLLY SHIT! SO MANY KINDS OF METHODS RESULT IN I DON'T KNOW WHICH TO CHOOSE.
Service之间可能是相互依赖的,如我们有一个Service,它的实现需要用到别的Service,这时需要按照如下方法进行服务的注册:
public static Indexer build(JobScheduler scheduler, FileSystem fileSystem) { IndexerImpl indexer = new IndexerImpl(fileSystem); scheduler.scheduleDailyJob(indexer); return indexer; }
如果我们依赖的Service有多个实现,那么我们就需要用到@ServiceId这个注解了:
public static Indexer build(@InjectService("JobScheduler")JobScheduler scheduler, @InjectService("FileSystem")FileSystem fileSystem) { IndexerImpl indexer = new IndexerImpl(fileSystem); scheduler.scheduleDailyJob(indexer); return indexer; }
如果有多个Service依赖了另外同一个Service的话,我们可以给module类追加一个构造器,并且把这个被依赖的Service作为它的构造参数。
@Marker
可以通过设定自定义的注解来帮助Tapestry去定位一个服务的实现。小猿没啥兴趣~
Tapestry有一个自定义的Marker——@Local,它会告诉Tapestry只允许找自己这个module中的实现~
advise
这是用来给service追加一些建议,保证的东西。
例如:给某些想要返回一个String类型的值得service方法追加一个判断,如果返回的是一个NULL的话,就返回一个空字符串
public static void adviseNonNull(MethodAdviceReceiver receiver) { ... }
这里面有几个问题
1 这个方法的返回值是void,且是static的。
2 这个方法的适用范围没有设定,所以追加适用范围@Match("*")或@Match("*DAO")。
3 建议内容没有设定,所以追加建议内容,是以内部类的方式来实现的,
MethodAdvice advice = new MethodAdvice(){ void advice(MethodInvocation invocation){ // 首先方法运行 invocation.proceed(); // 可以得到结果了,如果是null的话 if (getReturnValue().equals(null)) { invocation.setReturnValue(""); } } }
没有任何问题,什么时候触发这个advice呢?
4 设定触发条件,返回类型是String的时候。
for (Method method : receiver.getInterface().getMethods()) { if (method.getReturnType().equals(String.class)) { receiver.adviseMethod(method, advice); } }
所以结合起来:
/** * If the return value, of the method of some service, is null, then set it into "" */ @Match("*") public static void adviseNonNull(MethodAdviceReceiver receiver) { MethodAdvice advice = new MethodAdvice() { public void advise(MethodInvocation invocation) { invocation.proceed(); if (invocation.getReturnValue().equals(null)) { invocation.setReturnValue(""); } } }; // for those method of services of which the return type is String.class // Add the advice above for (Method method : receiver.getInterface().getMethods()) { if (method.getReturnType().equals(String.class)) { receiver.adviseMethod(method, advice); } } }
其它的一些advise
// LOG ADDING
@Match("*") public static void adviseLogging(LoggingAdvisor loggingAdvisor, Logger logger, MethodAdviceReceiver receiver) { loggingAdvisor.addLoggingAdvice(logger, receiver); }
// 所有DAO下面的service方法中如果标记了@CommitAfter就会自动将把业务提交
@Match("*Dao") public static void adviseTransactions(HibernateTransactionAdvisor advisor, MethodAdviceReceiver receiver) { advisor.addTransactionCommitAdvice(receiver); }