说实话,之前把AOP想的太简单太美好了,为了这个实现方式我前后抽时间研究了4天,虽然最后没能实现,但还是记录一下一些探索的经验,许在以后的项目中可以实施。先简单介绍一下
面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)——危急百科
我只了解了的AOP的三种实现方式,ASM(推荐文章),AspectJ(推荐文章)和SpringAOP(配置教程,详细用法)
- ASM没有去实践,本文不做讨论
- AspectJ
AspectJ需要特殊的编译,在我的项目里肯定是无法使用的,除此之外AspectJ还是很好用的,完全支持Java语法,学习成本低,但是我用不了TAT。 - SpringAOP
SpringAOP依赖于Spring框架,虽然把Spring框架用到我这系统也是不肯能的事情,但是本着学好Spring总是没有错的原则,我还是写了Demo,贴一下。
必要的依赖包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
spring-aspect.xml配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd ">
<mvc:annotation-driven/>
<!-- proxy-target-class="true"意思是打开CGLib代理,如果不配置这项,默认启用JDK代理,在代理对象时会抛异常,建议配置-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="registerFrame" class="com.gcoreinc.validate.RegisterFrame"/>
<bean id="userValidateAspect" class="com.gcoreinc.validate.UserValidateAspect" />
</beans>
定义切面
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class UserValidateAspect {
@Pointcut("execution(* com.gcoreinc.validate.RegisterFrame.doRegister(..))")
public void pointCut(){
}
//最全的功能了,可以对方法的传入参数进行处理,也可以获取方法的返回值,记住进入Around的方法如果不再次调用将不会执行,因此如果没有异常记得joinPoint.proceed()一下,执行此方法
@Around("pointCut()")
public void aroundRegister(ProceedingJoinPoint joinPoint){
System.out.println("around start");
Object[] args = joinPoint.getArgs();
if(args[0] != null){
User user = (User) args[0];
System.out.println(user.userName);
try {
joinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}else{
System.out.println("User can not be empty");
}
System.out.println("around end");
}
}
RegisterFrame类
package com.gcoreinc.validate;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class RegisterFrame extends JFrame{
JButton registerBtn;
public RegisterFrame() {
super("Register");
this.setSize(200, 200);
initComps();
doRegister(null);
}
private void initComps() {
registerBtn = new JButton("Register");
this.add(registerBtn);
registerBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
User user = new User("XiWenRen","12345678");
doRegister(user);
}
});
}
public void doRegister(User user){
System.out.println("goto register");
}
}
class User{
public User(String userName, String passWord){
this.userName = userName;
this.passWord = passWord;
}
public String userName;
public String passWord;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
'}';
}
}
测试类
package com.gcoreinc.validate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestAspect {
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext("classpath:spring-aspect.xml");
RegisterFrame frame = (RegisterFrame) context.getBean("registerFrame");
frame.setVisible(true);
frame.doRegister()
}
}
执行后发现控制台输出了:
around start
User can not be empty
around end
说明我们的切面成功了,但是,如果点击按钮之后,直接输出goto register
,切面没有成功,说明只能bean直接调用才能进入切面了,SpringAOP的这个特性,简直让人没法玩,解决方案是这样写
registerBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
User user = new User("XiWenRen","12345678");
ApplicationContext context = new FileSystemXmlApplicationContext("classpath:spring-aspect.xml");
RegisterFrame frame = (RegisterFrame) context.getBean("registerFrame");
frame.doRegister(user);
}
});
上下文的状态只能通过参数去传递了,这样的话痕迹还是很重的,这个方案也就只能到此为止了。
最近的状态真是差,思路不清晰,到今天第四天已经有些背离初衷了,究其原因还是已经整整一个月没有踢球了,这个周日一定要去找一场,恢复生气才能工作。
下一篇可能讨论一下使用代理模式的实现方式,或者想一个方法将观察者模式放入系统,等思路清晰后进行研究。