实现@Service、@Autowired、@Transactional注解类

目录

    • 什么是注解
      • 注解的基本元素
      • 元注解
        • @Target
        • Retention
    • 自定义注解实现
      • 声明注解
      • 改造demo
      • 测试

什么是注解

注解可以用来修饰类,方法,属性等,可以看做是一个特殊的标记,程序在编译或运行时检测到这些标记,从而进行一些特殊的操作。

注解的基本元素

1、修饰符,注解的修饰符必须是public,不写默认为public
2、关键字@interface
3、注解名称
4、注解内容
例如:

public @interface Service {
    String value() default "";
}

元注解

元注解可以用来修饰注解
一般注解用到的元注解有两个@Target和@Retention

@Target

用来表明该注解可以修饰的类型与范围
ElementType.TYPE
应用于类、接口(包括注解类型)、枚举
ElementType.FIELD
应用于属性(包括枚举中的常量)
ElementType.METHOD
应用于方法
ElementType.PARAMETER
应用于方法的形参
ElementType.CONSTRUCTOR
应用于构造函数
ElementType.LOCAL_VARIABLE
应用于局部变量
ElementType.ANNOTATION_TYPE
应用于注解类型
ElementType.PACKAGE
应用于包
ElementType.TYPE_PARAMETER
1.8版本新增,应用于类型变量)
ElementType.TYPE_USE
1.8版本新增,应用于任何使用类型的语句中

Retention

用于生命周期
RetentionPolicy.SOURCE
编译时被丢弃,不包含在类文件中
RetentionPolicy.CLASS
JVM加载时被丢弃,包含在类文件中,默认值
RetentionPolicy.RUNTIME
由JVM 加载,包含在类文件中,在运行时可以被获取到

自定义注解实现

我们根据以上注解的定义和属性来自我实现@Service@Autowired@Transactional功能
我们将原来的一个转账的demo基础上进行修改(详情:见博客 自定义Ioc/Aop)
我们之前的demo是通过读取beans.xml配置文件,实例化bean,通过类中的set方法,对其属性进行依赖注入,现在我们将通过@Service注解来实现实例化bean和通过@Autowired注解实现依赖注入,最后通过@Transactional注解实现事务控制

声明注解

@Service

// 作用于类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
    String value() default "";
}

@Autowired

// 作用于属性
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowried {
    boolean value() default true;
}

@Transactional

// 作用于类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {

}

改造demo

文件目录
实现@Service、@Autowired、@Transactional注解类_第1张图片

我们首先看一下beans.xml文件,对文件中的bean添加@Service注解,然后对beans.xml文件中的property标签对应的属性,添加@Autowired注解并且注释掉对应的set方法
实现@Service、@Autowired、@Transactional注解类_第2张图片
接着在我们要测试的方法对应的类上添加@Transactional注解,用来测试事务管理
例如:
实现@Service、@Autowired、@Transactional注解类_第3张图片
接下来是重点,改造BeanFactory

public class BeanFactory {
    public static Map map=new HashMap<>();
    // annotation 版本
    static {
        // 扫描bank文件夹下的类
        Reflections reflections = new Reflections("bank");
        try{
            // 获取带有Service注解的类
            Set> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Service.class);
            typesAnnotatedWith.forEach(beanService->{
                try {
                    // 实例化对象,并存入map中,以便之后使用
                    Object o = beanService.newInstance();
                    // 获取@Service value值,如果没有赋值默认是""
                    Service annotation = beanService.getAnnotation(Service.class);
                    String value = annotation.value();
                    // 判断,如果我们没有为类取别名,就读取类名
                    if(StringUtils.isEmpty(value)){
                        String name= beanService.getSimpleName();
                        // 判断是否是接口实现类,如果是用接口类名作为key,这样如果更换实现类的时候,由于我们使用接口类名作为key,
                        // 只需要将@service注解到新的实现类上,我们同样可以使用接口类名调用的到,不需要其他操作
                        Class[] interfaces = beanService.getInterfaces();
                        if(interfaces.length>0){
                          name=interfaces[0].getSimpleName();
                        }
                        // 将类名首字母小写,统一key的格式
                        value=(new StringBuilder()).append(Character.toLowerCase(name.charAt(0))).append(name.substring(1)).toString();
                    }

                    if (map.containsKey(value)){
                        System.out.println("@service注解value命名不能重复");
                    }else {
                        // 注入到map中
                        map.put(value,o);
                    }
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
            // 通过反射获取属性
            if(!map.isEmpty()){
                for(Map.Entry a: map.entrySet()){
                    Object value = a.getValue();
                    Class aClass = value.getClass();
                    // 使用反射技术,获取到类的全部属性
                    Field[] declaredFields = aClass.getDeclaredFields();
                    for (int i = 0; i 

修改动态代理ProxyFactory

@Service
public class ProxyFactory {
    @Autowried
    TransationManager transationManager;
    // jdk动态代理
public Object getJDKProxy(Object object){
    // 创建动态代理对象
    return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
            Class aClass = object.getClass();

            if(aClass.isAnnotationPresent(Transactional.class)){
                // 使用事务管理注解
                try{
                    // 打印被代理的对象
                    System.out.println(object.getClass());
                    // 打印被代理对象的执行方法
                    System.out.println(method.getName());
                    // 答应被代理对象的方法参数
                    for (int i = 0; i  aClass = object.getClass();

            if(aClass.isAnnotationPresent(Transactional.class)){
                try{
                    // 开启手动提交事务
                    transationManager.beginTransation();
                    // 执行方法
                    Object invoke = method.invoke(object, objects);
                    // 提交事务
                    transationManager.commitTransation();
                    return invoke;
                }catch (Exception e){
                    transationManager.rollbackTransation();
                    return null;
                }
            }else{
                Object invoke = method.invoke(o, objects);
                return invoke;
            }
        }
    });
}
public Object getProxy(Object object){
    // 判断走那种动态代理
    Class aClass = object.getClass();
    Class[] interfaces = aClass.getInterfaces();
    if(interfaces.length>0){
        // 使用jdkProxy动态代理
        Object jdkProxy = getJDKProxy(object);
        return jdkProxy;
    }else {
        // 使用cglib动态代理
        return getCglib(object);
    }
}
}

测试

    @Test
    public void annotationTest() throws SQLException {
        ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
        BankService bankService = (BankService) BeanFactory.getBean("bankService");
        BankService proxy = (BankService) proxyFactory.getProxy(bankService);
        Boolean transfer = proxy.transfer("6029621011001", "6029621011000", 100);
    }

执行前
实现@Service、@Autowired、@Transactional注解类_第4张图片
执行后
实现@Service、@Autowired、@Transactional注解类_第5张图片
实现@Service、@Autowired、@Transactional注解类_第6张图片
事务测试
实现@Service、@Autowired、@Transactional注解类_第7张图片
测试前
实现@Service、@Autowired、@Transactional注解类_第8张图片
测试后
实现@Service、@Autowired、@Transactional注解类_第9张图片
实现@Service、@Autowired、@Transactional注解类_第10张图片

回滚成功!

你可能感兴趣的:(Spring,java,spring,bean,事务,注解)