1.简介
在上篇文章中讲到了使用@Transactional注解失效的几种场景,其中有一个就是自身调用的问题,当时的解决办法就是使用@Autowired注解将本类注入到ioc容器中再调用方法,这样显然不太好,本篇文章中就讲一下在类内部生成代理类并使用。
2.代码演示
首先再来贴一下之前使用@Autowired将本类注入到ioc容器中使事务注解生效的场景
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private StudentService studentService;
@Autowired
private EmployeeServiceImpl employeeServiceImpl;
@Override
public void saveEmployee() {
Employee employee = new Employee();
employee.setId(UUIDUtils.getUuid());
employee.setAge(33);
employee.setName("li");
employee.setSalary(7000.53);
employeeMapper.saveEmployee(employee);
employeeServiceImpl.saveStudent();
}
@Transactional(rollbackFor = Exception.class)
private void saveStudent() {
Student student = new Student();
student.setId(UUIDUtils.getUuid());
student.setAge(44);
student.setName("timLi");
studentService.saveStudent();
}
在上述代码中使用@Autowired注解将本类EmployeeServiceImpl注入到了ioc容器中,然后使用employeeServiceImpl调用saveStudent()方法,使方法上的事务注解生效。
接下来在类内部生成代理类,使用代理类让事务注解生效
- SpringContextUtils工具类
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public SpringContextUtils() {
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String id) {
return applicationContext.getBean(id);
}
public static <T> T getBean(String id, Class<T> clz) {
return (T) applicationContext.getBean(id);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> clz) {
return applicationContext.getBean(clz);
}
public static Map getBeans(Class clz) {
return applicationContext.getBeansOfType(clz);
}
}
- 编写生成代理类的工具类BaseService<T>
public class BaseService<T> {
public BaseService() {
}
public T self() {
T bean = null;
try {
bean = (T) SpringContextUtils.getBean(this.getClass());
} catch (NoSuchBeanDefinitionException ex) {
Class[] clzs = this.getClass().getInterfaces();
if (clzs != null && clzs.length > 0) {
Map map = SpringContextUtils.getBeans(clzs[0]);
for (Object o : map.values()) {
Object obj = getTarget(o);
if (obj != null && this.getClass().getName().equals(obj.getClass().getName())) {
bean = (T) obj;
break;
}
}
}
if (bean == null) {
throw ex;
}
}
return bean;
}
private Object getTarget(Object bean) {
if (AopUtils.isAopProxy(bean)) {
AdvisedSupport adviserdSupport = this.getAdviserdSupport(bean);
Object tagetObject = null;
try {
tagetObject = adviserdSupport.getTargetSource().getTarget();
} catch (Exception e) {
e.printStackTrace();
new RuntimeException("Service内部调用获取selfBean失败: " + bean);
}
return this.getTarget(tagetObject);
} else if (bean != null) {
return bean;
} else {
return null;
}
}
private AdvisedSupport getAdviserdSupport(Object bean) {
AdvisedSupport advisedSupport = null;
try {
Field field = null;
if (AopUtils.isJdkDynamicProxy(bean)) {
field = bean.getClass().getSuperclass().getDeclaredField("h");
} else {
field = bean.getClass().getDeclaredField("CGLIB$CALLBACK_0");
}
field.setAccessible(true);
Object targetObject = field.get(bean);
Field advised = targetObject.getClass().getDeclaredField("advised");
advised.setAccessible(true);
advisedSupport = (AdvisedSupport) advised.get(targetObject);
} catch (Exception e) {
e.printStackTrace();
new RuntimeException("Service内部调用获取selfBean失败: " + bean);
}
return advisedSupport;
}
}
EmployeeServiceImpl继承BaseService<T>类
@Service
public class EmployeeServiceImpl extends BaseService<EmployeeServiceImpl> implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private StudentService studentService;
@Override
public void saveEmployee() {
Employee employee = new Employee();
employee.setId(UUIDUtils.getUuid());
employee.setAge(33);
employee.setName("li");
employee.setSalary(7000.53);
employeeMapper.saveEmployee(employee);
self().saveStudent();
}
@Transactional(rollbackFor = Exception.class)
public void saveStudent() {
Student student = new Student();
student.setId(UUIDUtils.getUuid());
student.setAge(44);
student.setName("timLi");
studentService.saveStudent();
}
}
使用BaseService<T>中的self()方法生成该类的代理类然后调用saveStudent()方法,这样的话事务注解也会生效。
3.寄语
这是我在项目中在类内部生成代理类的方法,其实千篇一律。如果小伙伴们有更好的工具类也欢迎分享,也欢迎小伙伴们的指正。