本文主要是带领读者实现一个小例子,来模拟 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;
这行注释去掉,引起异常。这样你就可以看到事务被回退了。