- 首先定義註解類(@Component等),參考Spring
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Repository {
String value() default "";
}
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean requred() default true;
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
Class<? extends Throwable>[] rollbackFor() default {};
}
- 一些基本工具類和實現類,並新增上註解
@Component
public class ConnectionUtils {
private final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
public Connection getCurrentThreadConn() throws SQLException {
Connection connection = threadLocal.get();
if(connection == null) {
connection = DruidUtils.getInstance().getConnection();
threadLocal.set(connection);
}
return connection;
}
}
@Component
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
public void beginTransaction() throws SQLException {
connectionUtils.getCurrentThreadConn().setAutoCommit(false);
}
public void commit() throws SQLException {
connectionUtils.getCurrentThreadConn().commit();
}
public void rollback() throws SQLException {
connectionUtils.getCurrentThreadConn().rollback();
}
}
@Component
public class ProxyFactory {
@Autowired
private TransactionManager transactionManager;
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public Object getJdkProxy(Object obj) {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
(proxy, method, args) -> {
Object result = null;
try{
transactionManager.beginTransaction();
result = method.invoke(obj,args);
transactionManager.commit();
}catch (Exception e) {
e.printStackTrace();
transactionManager.rollback();
throw e;
}
return result;
});
}
public Object getCglibProxy(Object obj) {
return Enhancer.create(obj.getClass(), (MethodInterceptor) (o, method, objects, methodProxy) -> {
Object result = null;
try{
transactionManager.beginTransaction();
result = method.invoke(obj,objects);
transactionManager.commit();
}catch (Exception e) {
e.printStackTrace();
transactionManager.rollback();
throw e;
}
return result;
});
}
}
@Service("transferService")
@Transactional(rollbackFor = Exception.class)
public class TransferServiceImpl implements TransferService {
@Autowired
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
Account from = accountDao.queryAccountByCardNo(fromCardNo);
Account to = accountDao.queryAccountByCardNo(toCardNo);
from.setMoney(from.getMoney()-money);
to.setMoney(to.getMoney()+money);
accountDao.updateAccountByCardNo(to);
int c = 1/0;
accountDao.updateAccountByCardNo(from);
}
}
@Repository("accountDao")
public class JdbcAccountDaoImpl implements AccountDao {
@Autowired
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
@Override
public int update(Money money) throws Exception {
Connection con = connectionUtils.getCurrentThreadConn();
String sql = "xxxx";
PreparedStatement preparedStatement = con.prepareStatement(sql);
preparedStatement.setInt(1,money.getMoney());
preparedStatement.setString(2,money.getId());
int i = preparedStatement.executeUpdate();
preparedStatement.close();
return i;
}
}
- 實現註解及事務,其中事務用到了動態代理,分為jdk和cglib兩種,其中jdk動態代理需要有介面類
public class BeanFactory {
private static final Map<String,Object> MAP = new HashMap<>();
private static final int COMPONENT = 1;
private static final int CONTROLLER = 2;
private static final int SERVICE = 3;
private static final int REPOSITORY = 4;
static {
try {
System.out.println("-========================================================================================");
List<Class<?>> classList = getClass("com.lossdate.learning");
Set<Class<?>> componentClassSet = getClassByType(COMPONENT, classList);
Set<Class<?>> repositoryClassSet = getClassByType(REPOSITORY, classList);
Set<Class<?>> serviceClassSet = getClassByType(SERVICE, classList);
Set<Class<?>> controllerClassSet = getClassByType(CONTROLLER, classList);
String[] nameSpilt;
for (Class<?> aClass : componentClassSet) {
Object o = aClass.newInstance();
Component annotation = aClass.getAnnotation(Component.class);
if(StringUtils.isNullOrEmpty(annotation.value())) {
nameSpilt = aClass.getName().split("\\.");
MAP.put(nameSpilt[nameSpilt.length - 1], o);
} else {
MAP.put(originNameWrapper(annotation.value()), o);
}
}
for (Class<?> aClass : repositoryClassSet) {
Object o = aClass.newInstance();
Repository annotation = aClass.getAnnotation(Repository.class);
if(StringUtils.isNullOrEmpty(annotation.value())) {
nameSpilt = aClass.getName().split("\\.");
MAP.put(nameSpilt[nameSpilt.length - 1], o);
} else {
MAP.put(originNameWrapper(annotation.value()), o);
}
}
for (Class<?> aClass : serviceClassSet) {
Object o = aClass.newInstance();
Service annotation = aClass.getAnnotation(Service.class);
if(StringUtils.isNullOrEmpty(annotation.value())) {
nameSpilt = aClass.getName().split("\\.");
MAP.put(nameSpilt[nameSpilt.length - 1], o);
} else {
MAP.put(originNameWrapper(annotation.value()), o);
}
}
for (Class<?> aClass : controllerClassSet) {
Object o = aClass.newInstance();
Controller annotation = aClass.getAnnotation(Controller.class);
if(StringUtils.isNullOrEmpty(annotation.value())) {
nameSpilt = aClass.getName().split("\\.");
MAP.put(nameSpilt[nameSpilt.length - 1], o);
} else {
MAP.put(originNameWrapper(annotation.value()), o);
}
}
for (Map.Entry<String, Object> classMap : MAP.entrySet()) {
Object aClass = classMap.getValue();
Class<?> c = aClass.getClass();
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
if(declaredField.isAnnotationPresent(Autowired.class) && declaredField.getAnnotation(Autowired.class).requred()) {
String[] nameArr = declaredField.getType().getName().split("\\.");
String name = nameArr[nameArr.length - 1];
Method[] methods = c.getMethods();
for (Method method : methods) {
if(method.getName().equalsIgnoreCase("set" + name)) {
method.invoke(aClass, MAP.get(name));
}
}
}
}
if(c.isAnnotationPresent(Transactional.class)) {
Class<?>[] interfaces = c.getInterfaces();
ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("ProxyFactory");
if(interfaces.length > 0) {
aClass = proxyFactory.getJdkProxy(aClass);
} else {
aClass = proxyFactory.getCglibProxy(aClass);
}
}
MAP.put(classMap.getKey(), aClass);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String originNameWrapper(String name) {
return name.substring(0,1).toUpperCase() + name.substring(1);
}
private static Set<Class<?>> getClassByType(int type, List<Class<?>> classList) {
Set<Class<?>> classSet = new HashSet<>();
classList.forEach(aClass -> {
Object annotation = null;
switch (type) {
case COMPONENT:
annotation = aClass.getAnnotation(Component.class);
break;
case CONTROLLER:
annotation = aClass.getAnnotation(Controller.class);
break;
case SERVICE:
annotation = aClass.getAnnotation(Service.class);
break;
case REPOSITORY:
annotation = aClass.getAnnotation(Repository.class);
break;
default: break;
}
if(annotation != null) {
classSet.add(aClass);
}
});
return classSet;
}
private static List<Class<?>> getClass(String packageName) throws ClassNotFoundException, IOException {
if(StringUtils.isNullOrEmpty(packageName)) {
throw new RuntimeException("無效的初始化路徑");
}
List<Class<?>> classList = new ArrayList<>();
String path = packageName.replace(".", "/");
Enumeration<URL> dirs;
dirs = Thread.currentThread().getContextClassLoader().getResources(path);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
if(url.getProtocol().equals("file")) {
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
loadClassFactory(packageName, filePath, classList);
}
}
return classList;
}
private static void loadClassFactory(String packageName, String path, List<Class<?>> classList) throws ClassNotFoundException {
File currentFile = new File(path);
File[] files = currentFile.listFiles(file -> file.isDirectory() || file.getName().endsWith(".class"));
if(files != null) {
String className;
Class<?> aClass;
for (File file : files) {
if(file.isDirectory()) {
loadClassFactory(packageName + "." + file.getName(), file.getAbsolutePath(), classList);
} else {
className = file.getName().replace(".class", "");
aClass = Class.forName(packageName + "." + className);
classList.add(aClass);
}
}
}
}
public static Object getBean(String id) {
return MAP.get(originNameWrapper(id));
}
}
- 最後測試類
public class MyTest {
@Test
public void test() throws Exception {
TransferService transferService = (TransferService) BeanFactory.getBean("transferService");
String fromId = "111";
String toId = "112";
int money = 100;
transferService.transfer(fromId, toId, money);
System.out.println(transferService);
}
}