使用代理_如何在类内部生成代理类并使用该代理类

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.寄语

这是我在项目中在类内部生成代理类的方法,其实千篇一律。如果小伙伴们有更好的工具类也欢迎分享,也欢迎小伙伴们的指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值