自定义@Service、@Autowired、@Transactional注解类和声明式事物

自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制,写到转账工程中,并且可以实现转账成功和转账异常时事务回滚

  1. 首先对注解类进行开发:

写自定义注解的代码,在写之前需要先了解以下两个元注解:

@Target

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。

作用:被描述注解的使用范围:

取值(ElementType)有:

1.CONSTRUCTOR:用于描述构造器

2.FIELD:用于描述域

3.LOCAL_VARIABLE:用于描述局部变量

4.METHOD:用于描述方法

5.PACKAGE:用于描述包

6.PARAMETER:用于描述参数

7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

 

@Retention

@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  作用:用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

取值(RetentionPoicy)有:

1.SOURCE:在源文件中有效(即源文件保留)

2.CLASS:在class文件中有效(即class保留)

3.RUNTIME:在运行时有效(即运行时保留)

Retention meta-annotation类型有唯一的value作为成员,它的取值来自Java.lang.annotation.RetentionPolicy的枚举类型值。

    以下是本项目对注解类进行开发:

    注解的声明周期采用的都是:RUNTIME,运行时有效

    @Autowired的注解使用范围是FIELD:用于描述域

    @Service和@Transactional的注解使用范围是TYPE:用于描述类

  1. 将xml中声明的bean转为注解的形式

比如TransferServiceImpl:

再来解释以下注解反射实现部分:

总共分三步:

  1. 扫描包下所有的@service,通过反射完成对象实例化
  2. 根据@Autowired完成注解的依赖关系
  3. 针对@Transactional,修改对象为对应的代理对象

/**
 *
声明静态方法,一开始就加载
 
* 方法一: 扫描注解解析
 
*/
static {
   
// 任务一:扫描包,通过反射技术实例化对象并且存储待用(map集合)
   
try{
       
//扫描获取反射对象集合
       
Reflections reflections = new Reflections("com.lagou.edu");
       
Set<Class<?>> servecesTypesAnnotatedWith = reflections.getTypesAnnotatedWith(Service.class);
        for
(Class<?> c : servecesTypesAnnotatedWith) {
           
// 通过反射技术实例化对象
           
Object bean = c.newInstance();
           
Service annotation = c.getAnnotation(Service.class);

           
//对象IDservice注解有value时用value,没有时用类名
           
if(StringUtils.isEmpty(annotation.value())){
               
//由于getName获取的是全限定类名,所以要分割去掉前面包名部分
               
String[] names = c.getName().split("\\.");
               
map.put(names[names.length-1], bean);
           
}else{
               
map.put(annotation.value(), bean);
           
}
        }
       
// 实例化完成之后维护对象的依赖关系Autowired,检查哪些对象需要传值进入,
       
for(Map.Entry<String, Object> a: map.entrySet()){
            Object o = a.getValue()
;
           
Class c = o.getClass();
           
//获取所有的变量
           
Field[] fields = c.getDeclaredFields();
           
//遍历属性,若持有Autowired注解则注入
           
for (Field field : fields) {
               
//判断是否是使用注解的参数
               
if (field.isAnnotationPresent(Autowired.class)
                        &&field.getAnnotation(
Autowired.class).required()) {
                    String[] names = field.getType().getName().split(
"\\.");
                   
String name = names[names.length-1];
                   
//Autowired注解的位置需要set方法,方便c.getMethods()获取
                   
Method[] methods = c.getMethods();
                    for
(int j = 0; j < methods.length; j++) {
                        Method method = methods[j]
;
                        if
(method.getName().equalsIgnoreCase("set" + name)) {  // 该方法就是 setAccountDao(AccountDao accountDao)
                           
method.invoke(o,map.get(name));
                       
}
                    }
                }
            }
           
//判断对象类是否持有Transactional注解,若有则修改对象为代理对象
           
if(c.isAnnotationPresent(Transactional.class)){
               
//获取代理工厂
               
ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
               
Class[] face = c.getInterfaces();//获取类c实现的所有接口
               
//判断对象是否实现接口
               
if(face!=null&&face.length>0){
                   
//实现使用JDK
                   
o = proxyFactory.getJdkProxy(o);
               
}else{
                   
//没实现使用CGLIB
                   
o = proxyFactory.getCglibProxy(o);
               
}
            }

           
// 把处理之后的object重新放到map
           
map.put(a.getKey(),o);
       
}
    }
catch (IllegalAccessException e) {
        e.printStackTrace()
;
   
} catch (InstantiationException e) {
        e.printStackTrace()
;
   
} catch (InvocationTargetException e) {
        e.printStackTrace()
;
   
}

}

 

最后演示下注解成果:

  1. 演示前先看下表中数据:

  1. 李向韩划款1000,操作成功

数据库显示

  1. 李向韩划款1000,操作失败

先调整代码:

操作失败:

数据库显示

说明转账异常时事务回滚成功。

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值