https://www.cnblogs.com/pickKnow/p/11138118.html
在這一篇博客中,已經通過AOP 思想了事務的功能,通過環繞通知,以及異常通知,實現能夠在指定的方法前后調用開啟事務,提交事務,回滾事務的功能。
在Spring中,已經通過注解@Transactional 實現了這一功能,具體spring.xml如下:
<!-- 配置事務 --> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 開啟事務 --> <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
代碼上只需在方法上加上:@Transactional
@Transactional public void addUser() { // 添加到數據庫 System.out.println("開始添加"); userDao.add(1, "tom", "12"); int i = 1 / 0; }
2,注解
分類:內置注解(也成為元注解 jdk 自帶注解)、自定義注解(Spring框架)
什么是內置注解
(1) @SuppressWarnings 再程序前面加上可以在javac編譯中去除警告--階段是SOURCE
(2) @Deprecated 帶有標記的包,方法,字段說明其過時----階段是SOURCE
(3)@Overricle 打上這個標記說明該方法是將父類的方法重寫--階段是SOURCE
@Overricle 案例演示
@Override
public String toString() {
return null;
}
@Deprecated案例演示
new Date().parse("");
@SuppressWarnings 案例演示
@SuppressWarnings({ "all" })
public void save() {
java.util.List list = new ArrayList();
}
實現自定義注解
元注解的作用就是負責注解其他注解。Java5.0定義了4個標准的meta-annotation類型,它們被用來提供對其它 annotation類型作說明。Java5.0定義的元注解:
@Target
@Target說明了Annotation所修飾的對象范圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述局部變量
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述參數
7.TYPE:用於描述類、接口(包括注解類型) 或enum聲明
2.@Retention
表示需要在什么級別保存該注釋信息,用於描述注解的生命周期(即:被描述的注解在什么范圍內有效)
3.@Documented
4.@Inherited
實現一個注解:
@Target({ElementType.METHOD}) //范圍 @Retention(RetentionPolicy.RUNTIME) //運行時候 要加 反射需要用到 @Inherited @Documented public @interface User { String username() default "tom"; int age() default 18; String[] arrays(); }
public class App { @User(username = "Jim", arrays = { "basketball" }, age = 20) public void addUser() { System.out.println("Annotation"); } public static void main(String[] args) throws ClassNotFoundException { // 獲取到class信息 Class<?> clazz = Class.forName("com.hella.thread.annotation.App"); // 獲取方法 Method[] methods = clazz.getDeclaredMethods(); // 循環遍歷每個方法上@User 的注解 for (Method method : methods) { User annotation = method.getDeclaredAnnotation(User.class); if (annotation != null) { System.out.println(annotation.age()); System.out.println(annotation.username()); } } } }
3,通過自定義注解來實現@Transactional 的功能
1,自定義注解
@Target({ ElementType.METHOD }) // 范圍 @Retention(RetentionPolicy.RUNTIME) // 運行時候 要加 反射需要用到 @Inherited @Documented public @interface DefTransactional { }
2,通過AOP 在每個方法調用前通過反射區獲取方法上是否有指定的自定義注解,如果有開啟事務,異常回滾事務
Component @Aspect // 這是一個切面類,用來監測方法的調用,調用前判斷是有@DefTransactional 注解 @Scope("prototype") // 保證事務的隔離性,讓每個對象都是一個新的對象,保證線程安全 public class AopDefTransactional { @Autowired private TransactionUtils transactionUtils; // 環繞通知 @Around("execution (* com.hella.thread.aoptransaction.service.UserService.*(..) )") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 1 找到對應的方法,通過方法名和參數類型 因為會有重載 TransactionStatus transactionStatus = begin(proceedingJoinPoint); proceedingJoinPoint.proceed(); // 4 提交事務 commit(transactionStatus); } // 異常通知 @AfterThrowing("execution (* com.hella.thread.aoptransaction.service.UserService.addUser(..) )") public void afterThrowing() { System.out.println("####自定義注解事務回滾"); transactionUtils.rollback(); } private void commit(TransactionStatus transactionStatus) { if (transactionStatus != null) { // 提交事務 System.out.println("####自定義注解事務提交"); transactionUtils.commit(transactionStatus); } } private TransactionStatus begin(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException, SecurityException { DefTransactional annotation = findMethodByProceedingJoinPoint(proceedingJoinPoint); if (annotation == null) { // 開啟事務 System.out.println("方法上沒有注解"); return null; } System.out.println("####自定義注解事務開啟"); TransactionStatus transactionStatus = transactionUtils.begin(); return transactionStatus; } private DefTransactional findMethodByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException, SecurityException { // 獲取到字節碼信息 Class<?> clazz = proceedingJoinPoint.getTarget().getClass(); // 獲取到方法名稱 String methodName = proceedingJoinPoint.getSignature().getName(); // 獲取參數 Class<?>[] par = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes(); // 獲取到正在執行的方法 Method method = clazz.getDeclaredMethod(methodName, par); DefTransactional annotation = method.getDeclaredAnnotation(DefTransactional.class); if (annotation == null) { System.out.println("沒有注解"); return null; } return annotation; } }
最后在方法上添加事務
@DefTransactional public void addUser() { // 添加到數據庫 System.out.println("開始添加"); userDao.add(1, "tom", "12"); int i = 1/0; }