注意:由于代码示例,这将是一个冗长的答案。
我创建了一个示例项目,可以从Scrum-Master.de下载。包结构如下:
如您所见,在主应用程序包de.scrum_master 下方有三个“主要”包common,feature1,feature2,每个包含子包pub(公共)和prv(私有)。此外,还有一个包含所有方面的aop包。每个pub/prv子包都包含一个虚拟类。
Java类如下:
package de.scrum_master.common.pub;
import de.scrum_master.common.prv.CommonPrivate;
import de.scrum_master.feature1.prv.Feature1Private;
import de.scrum_master.feature1.pub.Feature1Public;
import de.scrum_master.feature2.prv.Feature2Private;
import de.scrum_master.feature2.pub.Feature2Public;
public class Application {
private int id;
private String name;
public Application(int id, String name) {
super();
this.id = id;
this.name = name;
}
public static void main(String[] args) {
System.out.println(new Application (1, "Application"));
System.out.println(new CommonPrivate (2, "Common (private)"));
System.out.println(new Feature1Public (3, "Feature 1 (public)"));
System.out.println(new Feature1Private(4, "Feature 1 (private)"));
System.out.println(new Feature2Public (5, "Feature 2 (public)"));
System.out.println(new Feature2Private(6, "Feature 2 (private)"));
}
@Override
public String toString() {
return "Application [id=" + id + ", name=" + name + "]";
}
}
package de.scrum_master.common.prv;
public class CommonPrivate {
private int id;
private String name;
public CommonPrivate(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "CommonPrivate [id=" + id + ", name=" + name + "]";
}
}
package de.scrum_master.feature1.pub;
public class Feature1Public {
private int id;
private String name;
public Feature1Public(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Feature1Public [id=" + id + ", name=" + name + "]";
}
}
package de.scrum_master.feature1.prv;
import de.scrum_master.feature2.prv.Feature2Private;
import de.scrum_master.feature2.pub.Feature2Public;
public class Feature1Private {
private int id;
private String name;
public Feature1Private(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
new Feature2Private(11111, "This should be illegal");
new Feature2Public(22222, "This should be OK");
return "Feature1Private [id=" + id + ", name=" + name + "]";
}
}
package de.scrum_master.feature2.pub;
public class Feature2Public {
private int id;
private String name;
public Feature2Public(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Feature2Public [id=" + id + ", name=" + name + "]";
}
}
package de.scrum_master.feature2.prv;
import de.scrum_master.feature1.prv.Feature1Private;
import de.scrum_master.feature1.pub.Feature1Public;
public class Feature2Private {
private int id;
private String name;
public Feature2Private(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
new Feature1Private(33333, "This should be illegal");
new Feature1Public(44444, "This should be OK");
return "Feature2Private [id=" + id + ", name=" + name + "]";
}
}
现在我们需要我们的方面。更准确地说,我们需要一个抽象的基础方面和一个针对每个“主要”包的特定于包的具体子方面。这不是很好,但它有效。
抽象基础方面如下所示:
package de.scrum_master.aop;
public abstract aspect AccessController {
// All method/constructor calls to base package
pointcut basePackageCall():
call(* de.scrum_master..*.*(..)) || call(de.scrum_master..*.new(..));
// Method/constructor calls to public packages
pointcut publicPackageCall() :
call(* de.scrum_master..*.pub..*(..)) || call(de.scrum_master..*.pub..new(..));
// Own "major" package. Please override in concrete sub-aspect like this:
// within(de.scrum_master.mymajor..*)
pointcut ownPackage();
// Method/constructor calls within own "major" package. Please override in concrete sub-aspect like this:
// call(* de.scrum_master.mymajor..*(..)) || call(de.scrum_master.mymajor..new(..))
pointcut ownPackageCall();
pointcut forbiddenCall() :
ownPackage() && basePackageCall() && !(publicPackageCall() || ownPackageCall());
declare error: forbiddenCall() :
"Illegal call to non-public foreign major package";
}
正如你所看到的,有两个切入点必须由如下子方面具体化:
package de.scrum_master.aop;
public aspect AccessController_Common extends AccessController {
pointcut ownPackage() :
within(de.scrum_master.common..*);
pointcut ownPackageCall() :
call(* de.scrum_master.common..*(..)) || call(de.scrum_master.common..new(..));
}
package de.scrum_master.aop;
public aspect AccessController_Feature1 extends AccessController {
pointcut ownPackage() :
within(de.scrum_master.feature1..*);
pointcut ownPackageCall() :
call(* de.scrum_master.feature1..*(..)) || call(de.scrum_master.feature1..new(..));
}
package de.scrum_master.aop;
public aspect AccessController_Feature2 extends AccessController {
pointcut ownPackage() :
within(de.scrum_master.feature2..*);
pointcut ownPackageCall() :
call(* de.scrum_master.feature2..*(..)) || call(de.scrum_master.feature2..new(..));
}
为新的“主要”包创建子方面就像复制和粘贴以及对相应包名称的小编辑一样简单。
如果你检查一下Application.main
,你Feature1Private.toString
会Feature2Private.toString
发现我在那里构建了一些非法调用非公开的外国子包,总共四个。在 Eclipse 的问题视图中看起来像这样:
关于基本/子方面的更多话:虽然在建议中可以动态确定包名称并通过反射做一些更多的魔术,但declare error
它基于可以在编译时静态确定的切入点。因此,我们必须在这里更加具体和明确,这要求我们为场景中的每个“主要”包都有一个子方面。替代方案将是一个包含每个单个包的切入点的大具体方面。我认为这看起来很难看。
现在享受我的解决方案,我认为它充分解决了您的问题。:-)