如何做优化网站排名,海南千筑建设工程有限公司网站,码制作官网,自己0基础怎么创业AspectJ 通过连接点向Java添加一些新的程序元素来扩展Java#xff0c;是Java面向切点一种实现。其主要包括连接点、切点、建议、切面及类型间声明。
连接点#xff1a;程序在执行过程中明确的点。包括方法和构造函数调用及字段访问等。
切点#xff1a;用来挑选连接点。
… AspectJ 通过连接点向Java添加一些新的程序元素来扩展Java是Java面向切点一种实现。其主要包括连接点、切点、建议、切面及类型间声明。
连接点程序在执行过程中明确的点。包括方法和构造函数调用及字段访问等。
切点用来挑选连接点。
建议在程序运行到由切点挑选的连接点时执行的程序片段。
切面类似于类成员包含了连接点、切点及切面等。
类型间声明静态改变类的结构及层级关系。 可以为已有的类定义新的成员、方法。也可以使其继承新的类及实现接口。
1 AspectJ 语法
aspectJ 需要使用ajc编译器进行编译。
1.1 切点
切点类似于类中的方法有访问权限修饰符、可以被定义为final但也有些不同1不能重载。2作用域包括切面声明及主体方法的作用域是在类主体。 if 条件判断 within witin(全限定名)在某个类的全部连接点。 cflow cflow(pointcut), 连接点pointcut 及之后的且在其封闭区间内的所有连接点。包括在在该方法中所调用的其他方法的连接点。 get 当某个字段被访问时会被捕获。不能捕获参数 set 当某个字段被赋值时会被捕获。可以捕获参数 handler try..catch中的catch捕获的错误类型是Throwable类型及其子类型时不被捕获。可以捕获参数 adviceexecution adviceexecution() 所有建议在执行时会被捕获。
表 切点的部分语法
public class PointcutEntity {private String name;public void fun(String val) {this.name val;fun();System.out.println(-----);}private void fun() {System.out.println(this.name);}public void fun2() {System.out.println(fun2);try {throw new Throwable();} catch (Throwable e) {System.out.println(处理);}}
}public aspect PointcutEntityAspect perthis(withPointcut()){ // 相当于全局声明了在这个切面中所有的连接点都在PointcutEntity里运行final pointcut withPointcut(): within(service.PointcutEntity); // PointcutEntity内的所有连接点pointcut funPointcut(): execution(* service.PointcutEntity.fun());pointcut cFlowPointcut(): cflow(funPointcut()); // funPointcut 连接点及之后切在封闭区间内的所以连接点pointcut getPointcut(): get(String service.PointcutEntity.name); // 捕获PointcutEntity的name字段被访问pointcut setPointcut(String name): set(String service.PointcutEntity.name) args(name); // 捕获PointcutEntity的name字段被赋值pointcut handlerPointcut(Throwable e): handler(Throwable) args(e); // try..catch中的catch捕获的错误类型是Throwable类型及其子类型时不被捕获// before(): cFlowPointcut() {
// System.out.println(cFlowPointcut---);
// System.out.println(thisJoinPoint.getSourceLocation());
// System.out.println(thisJoinPoint.getSignature());
// System.out.println(thisJoinPoint.getKind());
// System.out.println();
// }// before(): getPointcut() {
// System.out.println(getPointcut---);
// System.out.println(thisJoinPoint.getSourceLocation());
// System.out.println(thisJoinPoint.getSignature());
// System.out.println(thisJoinPoint.getKind());
// System.out.println();
// }// before(String name): setPointcut(name) {
// System.out.println(getPointcut---);
// System.out.println(赋值value: name);
// System.out.println(thisJoinPoint.getSourceLocation());
// System.out.println(thisJoinPoint.getSignature());
// System.out.println(thisJoinPoint.getKind());
// System.out.println();
// }before(Throwable e): handlerPointcut(e) {System.out.println(handlerPointcut---);System.out.println(抛错: e);System.out.println(thisJoinPoint.getSourceLocation());System.out.println(thisJoinPoint.getSignature());System.out.println(thisJoinPoint.getKind());System.out.println();}public static void main(String[] args) {PointcutEntity pointcutEntity new PointcutEntity();pointcutEntity.fun2();}
}
1.2 建议
有三种类型before、after包括 after() returning、after() throwing及after及around。around 可以替换方法的返回值。
public class AdviceEntity {public String fun() {System.out.println(fun);return 建议;}public void fun1() throws ClassNotFoundException {System.out.println(fun1);throw new ClassNotFoundException();}public String fun2() {System.out.println(fun2);return fun2;}
}public aspect AdviceEntityAspect {pointcut funPointcut(): execution(* service.AdviceEntity.fun*(..));pointcut fun2Pointcut(): execution(* service.AdviceEntity.fun2(..));after() returning (String val): funPointcut() {System.out.println(after() returning);System.out.println(返回值 val);System.out.println(thisJoinPoint.getSourceLocation());System.out.println(thisJoinPoint.getSignature());System.out.println();}after() throwing (ClassNotFoundException e): funPointcut() {System.out.println(after() throwing);System.out.println(捕获错误 e);System.out.println(thisJoinPoint.getSourceLocation());System.out.println(thisJoinPoint.getSignature());System.out.println();}String around(): fun2Pointcut() {System.out.println(String around());System.out.println(thisJoinPoint.getSourceLocation());System.out.println(thisJoinPoint.getSignature());System.out.println();return around() String;}public static void main(String[] args) throws ClassNotFoundException {AdviceEntity entity new AdviceEntity();entity.fun();System.out.println(fun2的返回值 entity.fun2());entity.fun1();}
}
1.3 类型间声明
AspectJ 可以为类定义方法及字段可以使其继承新的类及实现接口。
public class InterEntity {private final String name inter_entity;public void fun() {System.out.println(InterEntity定义的name: this.name);this.speak(); // 在类中可以直接使用在切面中定义的方法}
}public interface SpeakInterface {void speak();
}public aspect InterEntityAspect {private String InterEntity.name InterEntityAspect; // 给AdviceEntity定义name字段虽然这个字段在原结构已存在// 但是因为这里和AdviceEntity中其访问类型是private所以不会冲突declare parents: InterEntity implements SpeakInterface; // 定义实现接口还需要定义实现该接口的方法public void InterEntity.speak() { // 上面接口方法的实现System.out.println(InterEntityAspect );}private void InterEntity.show() {// 这里的this 是指InterEntity的实例System.out.println(this.name); // InterEntityAspectthis.fun(); // InterEntity定义的name:inter_entitythis.speak();}public static void main(String[] args) {InterEntity interEntity new InterEntity();interEntity.show();}
}
declare soft: Type: Pointcut; 捕获类型为Type的异常并且重抛成SoftException。Type 不能是RuntimeException。
declare precedence: TypePatternList; 为切面定义优先级TypePatternList为切面列表“”隔开越前面优先级越高。
public class DeclareEntity {public void fun() {System.out.println(fun);}public void fun(int num) throws CustomException {if (num 0) throw new CustomException();System.out.println(33 / num);}
}public abstract aspect DeclareEntityParentAspect pertarget(DeclareEntityClassPointcut()){pointcut DeclareEntityClassPointcut(): within(service.DeclareEntity);pointcut funPointCut(): execution(* fun(..));declare precedence: DeclareEntityChildrenAspectB,DeclareEntityChildrenAspectA; // 定义切面的优先级declare soft:CustomException: funPointCut();public static void main(String[] args) throws CustomException {DeclareEntity entity new DeclareEntity();entity.fun();entity.fun(0);}
}public aspect DeclareEntityChildrenAspectA extends DeclareEntityParentAspect{before(): funPointCut() {System.out.println(DeclareEntityChildrenAspectA);System.out.println(thisJoinPoint.getSourceLocation());System.out.println();}
}public aspect DeclareEntityChildrenAspectB extends DeclareEntityParentAspect{before(): funPointCut() {System.out.println(DeclareEntityChildrenAspectB);System.out.println(thisJoinPoint.getSourceLocation());System.out.println();}
}1.4 切面
切面像类一样也可以被继承被继承的切面须为抽象切面。 也可以继承类及实现接口。 [issingleton()] 默认类型将不限定切点。 perthis(Pointcut) 全局限定连接点在this(Pointcut)中。 pertarget(Pointcut) 全局限定连接点在target(Pointcut)中。 percflow(Pointcut) 全局限定连接点在cflow(Pointcut)z中。 percflowbelow(Pointcut) 全局限定连接点在cflowbelow(Pointcut)中。
图 五种在切面中全局限定连接点的方式
2 AspectJ 的应用场景
2.1 开发阶段
我们在开发过程中需要进行调试有时会往业务代码中插入跟踪代码。在上线的时候我们要把这些代码删除否则可能会降低系统性能。有时我们插入的代码会比较多和广可能会漏删这些代码。因为有些人常常会通过写脚本的方式来进行调试。
而AspectJ 在这方面具有独特的优势可以实现对调试代码的“插拔”。
需求打印develop.service 包下所有类以get或set开头方法访问日志。
public class Student {private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;}
}public class Teacher {private String name;private String course;public String getName() {return name;}public void setName(String name) {this.name name;}public String getCourse() {return course;}public void setCourse(String course) {this.course course;}
}public class GetAndSetTrace {public static void info(String className,String methName,String location,Object result,Object... args) {String sb 访问时间 new Date() \n 类名 className \n 方法 methName \n;if (args ! null) sb 参数名 Arrays.asList(args) \n;if (result ! null) sb 返回值 result \n;sb 连接点 location;System.out.println(sb);System.out.println(--------------------);}
}public aspect GetAndSetTraceAspect pertarget(targetClassPointcut()){pointcut targetClassPointcut(): within(develop.service.*);pointcut getPointcut(): execution(Object get*());pointcut setPointcut(Object obj): execution(void set*(*)) args(obj);after() returning(Object obj): getPointcut() {trace(thisJoinPoint,obj);}before(Object obj): setPointcut(obj) {trace(thisJoinPoint,null);}private void trace(JoinPoint joinPoint,Object result) {String className joinPoint.getTarget().getClass().getName();String methodName joinPoint.getSignature().toShortString();String location joinPoint.getSourceLocation().getLine() ;GetAndSetTrace.info(className,methodName,location,result,joinPoint.getArgs());}public static void main(String[] args) {Student student new Student();Teacher teacher new Teacher();student.setName(小名同学);student.setAge(18);teacher.setName(刘老师);teacher.setCourse(英语);System.out.println(学生 student.getName());System.out.println(年龄 student.getAge());System.out.println(教师 teacher.getName());System.out.println(课程 teacher.getCourse());}
}AspectJ 可重用比如上面需求有改动对日志打印格式及要求传递的参数做了修改。如果不使用Aspect而使用传统方式-往业务代码插入跟踪代码。那么每个被插入的跟踪代码都需要修改。而对于AspectJ 就仅仅修改相关切面及跟踪类即可。
2.2 生产阶段
观察者模式有两种角色Subject目标类被观察的对象Observer 观察者将观察的目标的改变而做出改变。
PropertyChangeSupport和PropertyChangeListener类是Java中用来监听对象属性变化的。
public class User {private String name;private final PropertyChangeSupport propertyChangeSupport new PropertyChangeSupport(this);public void addPropertyChangeListener(PropertyChangeListener listener) {propertyChangeSupport.addPropertyChangeListener(listener);}public void setName(String name) {propertyChangeSupport.firePropertyChange(name,this.name,name);this.name name;}public String getName() {return name;}public static void main(String[] args) {User user new User();PropertyChangeListener listener new PropertyChangeListener() {Overridepublic void propertyChange(PropertyChangeEvent evt) {System.out.println(evt.getPropertyName() 发生了改变旧值 evt.getOldValue() 新值 evt.getNewValue());}}; // 监听器user.addPropertyChangeListener(listener);user.setName(黄先生);user.setName(刘女士);}
}
我们可以使用AspectJ 实现上面的功能。
public aspect PropertyChangeAspect{private SetPropertyChangeObserver User.observerSet new HashSet();public void User.addListener(PropertyChangeObserver observer) {observerSet.add(observer);}public SetPropertyChangeObserver User.getListenerSet() {return this.observerSet;}pointcut setMethod(Object arg): execution(* set*(*)) args(arg);before(Object org): setMethod(org) {Object target thisJoinPoint.getTarget();if (target instanceof User) {for(PropertyChangeObserver listener : ((User) target).getListenerSet()) {listener.update(thisJoinPoint.getSignature().getName(),org);}}System.out.println();}public static void main(String[] args) {User user new User();PropertyChangeObserver observer1 (methodName, arg) - {System.out.println(观察者1方法 methodName ,参数 arg);};PropertyChangeObserver observer2 new PropertyChangeObserver() {Overridepublic void update(String methodName, Object arg) {System.out.println(观察者2参数 arg);}};user.addListener(observer1);user.addListener(observer2);user.setName(黄);user.setName(刘);}// 自定义建设者interface PropertyChangeObserver {void update(String methodName,Object arg);}
}