自定义注解(Annotation标签),实现AOP切面编程,完成事务代理

灵魂拷问:
       AOP切面编程是什么?
       自定义注解是什么?怎么实现功能?

1. 如何理解AOP切面编程?

       AOP本质是一种编程思想,横向提取机制,将横切逻辑和业务代码进行分离,解耦合,不变原有业务逻辑的情况下,进行动态代理增强横切逻辑代码避免重复,实现业务增强。
       例:下面将要实现的事务控制,项目中不同业务需要启用事务时,不使用动态代理进行业务增强,那么每实现一个业务,都要进行一次事务管理,那么将会冗余很多代码。

2. 自定义注解是什么?怎么实现功能?

       注解的本质就是一个修饰符,一个标签而已,注解本身不会做任何事情,不会实现任何逻辑,只是存在于源文件中。
       那么注解标记声明对象后是一个怎么样的执行逻辑呢?拿Spring @Transactional 事务注解来举例,当注解标注Impl类中方法后。在Spring IOC容器初始化时,会识别到注解标志,对有注解的标志的Impl实例对象,或者是类对象进行一次动态代理,完成之后再放入到IOC容器中,最终代码执行时,调用的是做过动态代理的实例对象,这样来实现对业务代码进行事务管理,逻辑增强。话不多说,下面上代码。

3. 可能用到的类型判断函数

  • 类型判断: Instance of ,判断当前实例对象是否是xx类对象实例

     ServiceInterfaceImpl serviceInterfaceImpl = new ServiceInterfaceImpl();
     boolean flag = serviceInterfaceImpl instanceof ServiceInterface;
     boolean flag1 = serviceInterfaceImpl instanceof ServiceInterfaceImpl;
    
  • 类型判断:isAssignableFrom 判断当前类对象,是否是本类,或者是实现类

     Class impl = ClassLoader.getSystemClassLoader().loadClass("com.huey.annotation.ServiceInterfaceImpl");
     Class inter = ClassLoader.getSystemClassLoader().loadClass("com.huey.annotation.ServiceInterface");
     Class pro = ClassLoader.getSystemClassLoader().loadClass("com.huey.annotation.TransactionalProxy");
     System.out.println(inter.isAssignableFrom(impl));
     System.out.println(impl.isAssignableFrom(impl));
     System.out.println(impl.isAssignableFrom(inter));
     System.out.println(pro.isAssignableFrom(impl));
    

4. 动态代理返回对象

        动态代理代理实例对象,返回的也是实例对象。
        动态代理,代理类对象,返回的是类对象。
        若是要对返回的Object对象操作,获取到的最终都是proxy代理对象
        测试代码下面贴出
在这里插入图片描述

5. 自定义注解,完成事务代理简单示例代码

//接口类
public interface ServiceInterface {
    void updateDatasource();
}
//接口实现类
public class ServiceInterfaceImpl implements ServiceInterface {
    @Transcational
    public void updateDatasource() {

        System.out.println("第一次请求sql");

        //故意执行错误程序
        int a = 1 / 0;

        System.out.println("第二次请求sql");
    }
}
//动态代理类
public class TransactionalProxy {

    public Object JDBCProxy(final Object obj) {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("进入动态代理类");

                System.out.println("开启事务");

                Object result;
                try {
                    result = method.invoke(obj, args);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("回滚事务");
                    throw e;
                }

                System.out.println("结束事务");
                return result;
            }
        });
    }
}
//注解类
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transcational {

    String value() default "";
}
//测试类
public class TranscationalTest {

    private ServiceInterface serviceInterface;

    @Test
    public void test() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        //第一步,加载Class类对象
        Class serviceClazz = Class.forName("com.huey.annotation.ServiceInterfaceImpl");
        Class testClazz = Class.forName("com.huey.TranscationalTest");

        //第二步实例化类对象
        Object serviceBean = serviceClazz.newInstance();
        Object testBean = testClazz.newInstance();

        //第三步对类进行扫描,检测事务注解      这里直接对事务注解类操作(简单样例)
        //获取到类中所有生声明的方法
        Method[] methods = serviceClazz.getDeclaredMethods();
        for (Method method : methods) {
            //判断是否存在事务注解
            Transcational transcational = method.getAnnotation(Transcational.class);
            if (transcational != null) {
                //第四步步对serviceBean实体,进行动态代理
                TransactionalProxy transactionalProxy = new TransactionalProxy();
                serviceBean = transactionalProxy.JDBCProxy(serviceBean);
//                测试动态代理返回值的部分代码
//                Object o = transactionalProxy.JDBCProxy(serviceClazz);
//                System.out.println(serviceBean);
//                System.out.println(serviceBean.getClass().getSimpleName());
//                System.out.println(o);
//                System.out.println(o.getClass().getSimpleName());
            }
        }


        //第五步,将serviceBean实例注入到test实例中
        //获取Test类对象中声明的属性对象
        Field field = testClazz.getDeclaredField("serviceInterface");
        //判断,找到当前属性对象(Interface)的实现实例  (简单示例是不用写的,这里有个函数特别提出来一下)
        if (field.getType().isAssignableFrom(serviceClazz)) {
            //进行属性注入
            field.setAccessible(true);
            field.set(testBean, serviceBean);
        }

        //以上步骤均可理解为工程启动时,进行的默认加载配置
        //第六步进行测试
        //因为这里TranscationalTest是没有进行管理的,所以对它的实例对象进行一次变化
        TranscationalTest transcationalTest = (TranscationalTest) testBean;
        transcationalTest.serviceInterface.updateDatasource();
    }
}

/**
数据库操作异常输出结果
进入动态代理类
开启事务
第一次请求sql
回滚事务
Caused by: java.lang.ArithmeticException: / by zero
	at com.huey.annotation.ServiceInterfaceImpl.updateDatasource(ServiceInterfaceImpl.java:12)


数据库正常操作输出结果
进入动态代理类
开启事务
第一次请求sql
第二次请求sql
结束事务

Process finished with exit code 0
*/

总结:
       以上则是整个自定义注解实现事务代理的一个过程。需要注意的是注解本身是不实现任何功能的,只是做一个标记而已,功能的实现都是在初始化的时候,通过对标签注解的判断,通过对实例对象,或者类对象的一个动态代理进行实现。
       AOP切面编程就是一个编程思想,借助动态代理进行业务逻辑,横切逻辑的一个分离,达到解耦的目的,对业务进行增强。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值