本文主要是带领读者实现一个小例子,来模拟 Spring 框架的面向切面编程(AOP)。实现过程中用到了 Java 的动态代理。
整个项目由maven管理。 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>zhangchao</groupId> <artifactId>AOP</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> </project>目录结构
src/main/java │ └─ zhangchao │ ├─ dao │ └ UserDao.java │ ├─ framework │ ├ Factory.java │ ├ TransactionInterceptor.java │ └ ZcInvocationHandler.java │ ├─ po │ └ User.java │ ├─ service │ ├─ impl │ │ └ UserServiceImpl.java │ │ │ └─ UserService.java │ └─ Main.java实体类User
package zhangchao.po; public class User { String id; String name; Integer age; }UserDao封装数据库操作
package zhangchao.dao; public class UserDao { public void save() { System.out.println("save user"); } }工厂类Factory。这里使用了 Java 动态代理。表面上看是根据className返回每个类对应生成的对象,事实上是返回的是代理对象。每当生成代理对象的时候,就会调用接口InvocationHandler的invoke方法。
package zhangchao.framework; import java.lang.reflect.Proxy; public final class Factory { public final static Object getBean(String className) { Object bean = null; try { Class<?> c = Class.forName(className); Object realBean = c.newInstance(); bean = Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), new ZcInvocationHandler(realBean)); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bean; } }ZcInvocationHandler类实现了InvocationHandler接口。在继承的invoke方法里,所有save字符串开头的方法都要做事务处理。事务处理的代码在TransactionInterceptor类中。
package zhangchao.framework; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ZcInvocationHandler implements InvocationHandler { private Object bean; TransactionInterceptor ti = new TransactionInterceptor(); ZcInvocationHandler(Object bean) { this.bean = bean; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.startsWith("save")) { ti.begin(); try { method.invoke(bean, args); ti.commit(); } catch (Exception e) { ti.rollBack(); } } else { method.invoke(bean, args); } return null; } }TransactionInterceptor类用来处理事务。
package zhangchao.framework; public class TransactionInterceptor { public void begin () { System.out.println("开始事务"); } public void commit() { System.out.println("提交事务"); } public void rollBack() { System.out.println("回滚事务"); } }服务类的接口:
package zhangchao.service; import zhangchao.po.User; public interface UserService { void save(User user); }服务类的实现:
package zhangchao.service.impl; import zhangchao.dao.UserDao; import zhangchao.po.User; import zhangchao.service.UserService; public class UserServiceImpl implements UserService { private UserDao userDao = new UserDao(); public void save(User user) { userDao.save(); // int r = 4/0; } }Main.java
package zhangchao; import zhangchao.framework.Factory; import zhangchao.po.User; import zhangchao.service.UserService; public class Main { public static void main(String[] args) { UserService userDao = (UserService)Factory.getBean("zhangchao.service.impl.UserServiceImpl"); userDao.save(new User()); } }在 UserServiceImpl 类中,可以把 int r = 4/0; 这行注释去掉,引起异常。这样你就可以看到事务被回退了。