【Spring07】Spring注解开发

注解的核心作用在于简化开发步骤,使用注解可以省去一些不必要的配置。

1 注解所需配置

<context:component-scan bean-package="com.qianglj"/>
  • 告知Spring注解的位置;

  • Spring会去解析package="com.qianglj"包下的所有注解;

<tx:annotation-driven transaction-manager="tx"/>
  • 指定事务管理器tx

  • 配置后使@Transactional注解生效;

<aop:aspectj-autoproxy/>
  • 开启AOP的相关注解。

2 声明bean相关注解

此类注解用于替换掉自建类组件的<bean>标签,可以更快的声明bean。

  • @Service:业务类专用;

  • @Repository:dao实现类专用;

  • @Controller:web层专用;

  • @Component:通用。

以上四个注解除了名字不一样之外,用法、功能完全一致,例如:

@Service
public class UserServiceImpl implements UserService {

此处的@Service注解相当于声明一个<bean id="userService" class="xxx.xx.xx.UserServiceImpl">bean标签。

  • 默认的beanId是类名的首字母小写,也可以显式声明beanId,例如@Service("userService666");

  • 还可以配合@Scope注解进行使用来声明创建模式:

    • @Scope("singleton"):单例模式创建,默认;

    • @Scope("prototype"):多例模式创建。

3 注入(DI)相关注解

此类注解用于完成bean中属性值的注入。

  • @Autowired:基于类型的自动注入;

    • 如果工厂中由多个相同类型的bean,可以配合@Qualifier注解使用来限定要自动注入的bean的id,例如:

@Autowired
@Qualifier("userDao006")
private UserDao userDao;

表示有如果由多个类型为UserDao类型的bean,从中挑取beanId为userDao666的bean进行注入;

  • @Resource:基于名称的自动注入;

    • 默认注入与属性同名的bean,例如:

@Resource
private UserDao userDao;
    • 也可以指定名称注入,例如:
@Resource(name="userDao666")
private UserDao userDao;
  • @Value:可以对简单数据类型(基本数据类型、String、Date)进行注入;
@Value("666")
private Integer id;

4 事务控制相关注解

事务控制注解一般用于Servcie层,用于控制事务切入。

  • @Transactional

    • 如果使用了此注解,那么工厂配置中的<tx:advice...aop:config...可以省略;

    • 可以设置事务的一系列属性,例如isolationpropagation等;

    • 写在类名上,表示该类中的每一个方法都切入相同的事务控制;

    • 写在类中的方法名上,表示该方法有自己的事务控制,此时即使类名上有事务控制的注解也是无效的。

5 AOP相关注解

5.1 一般注解

使用AOP相关注解可以更方便地定制切面。

例如如下切面类:

@Aspect // 声明此类是一个切面类:会包含切入点(pointcut)和通知(advice)
@Component //声明组件,进入工厂
public class MyAspect {
    // 定义切入点
    @Pointcut("execution(* com.qf.service.UserServiceImpl.*(..))")
    public void pc(){}

    @Before("pc()") // 前置通知
    public void mybefore(JoinPoint a) {
        System.out.println("target:"+a.getTarget());
        System.out.println("args:"+a.getArgs());
        System.out.println("method's name:"+a.getSignature().getName());
        System.out.println("before~~~~");
    }

    @AfterReturning(value="pc()",returning="ret") // 后置通知
    public void myAfterReturning(JoinPoint a,Object ret){
        System.out.println("after~~~~:"+ret);
    }

    @Around("pc()") // 环绕通知
    public Object myInterceptor(ProceedingJoinPoint p) throws Throwable {
        System.out.println("interceptor1~~~~");
        Object ret = p.proceed();
        System.out.println("interceptor2~~~~");
        return ret;
    }
    @AfterThrowing(value="pc()",throwing="ex") // 异常通知
    public void myThrows(JoinPoint jp,Exception ex){
        System.out.println("throws");
        System.out.println("===="+ex.getMessage());
    }
}
  • @Aspect:定义在类名之上,声明此类是一个切面类,会包含切入点(point cut)和通知(advice);

  • @Pointcut:一般会定义在一个自定义空方法上,如public void pc(){},定义切入点,这个方法会被看做是切入点表达式的别名。在其他的通知注解中,可以使用方法名称表示这个切入点表达式;

5.2 @Before

@Before:前置通知

  • 属性:

    • value,表示切面的执行位置,值可以是切入点表达式,也可以是切入点方法;

  • 特点:

    • 定义在切面方法上面;

    • 在目标方法之前执行切面方法;

    • 不会影响目标方法的执行;

切面类中的通知方法,可以有参数JoinPoint。表示正在执行的业务方法,相当于反射中的Method,使用时要求必须是参数列表的第一个参数。通过这个JoinPoint可以获取方法执行时的信息,例如方法的名称,方法的参数集合:

@Before("execution(* *.SomeServiceImpl.do*(..))")
public void myBefore1(JoinPoint joinPoint) {
    System.out.println("带参数的通知方法");
    System.out.println("====================");
    System.out.println("获取目标方法的定义" + joinPoint.getSignature());
    System.out.println("获取方法的名称"+joinPoint.getSignature().getName());
    System.out.println("获取方法执行时参数");
    Object[] argsArr = joinPoint.getArgs();
    for (Object o:argsArr){
        System.out.print(o+"\t");
    }
    System.out.println();
    System.out.println("====================");
}

5.3 @AfterReturning

@AfterReturning:后置通知

  • 属性:

    • value,切入点表达式,同前置通知注解;

    • returning,自定义变量,表示目标方法的返回值;要求:自定义变量名称必须和通知方法的形参名一样;

  • 特点:

    • 定义在切面方法的上面;

    • 在目标方法之后执行;

    • 能获取到目标方法的执行结果;

    • 不会影响目标方法的执行;

@AfterReturning(value = "execution(* SomeServiceImpl.do*(..))", returning = "res")
public void myAfterReturning(Object res) {
    //        修改res的值不影响目标方法的返回值
    if (res != null) {
        res = "Hello Aspectj";
    }
    System.out.println("后置通知,获取到方法的返回值" + res);
}

后置通知也可以有参数JoinPoint,但是如果有的话,必须在第一个。

5.4 @Around

@Around:环绕通知

  • 属性:

    • value,切入点表达式,同前置通知注解;

  • 环绕通知方法定义要求:

    • public;

    • 必须有返回值,推荐使用Object类型, 表示调用目标方法希望得到的执行结果(不一定是目标方法自己的返回值);

    • 名称必须自定义;

    • 必须有ProceedingJoinPoint参数,相当于反射中的Method作用等同于Method.invoke()

  • 特点:

    • 在目标方法的前和后都能增加功能;

    • 能够控制目标方法是否执行;

    • 能够修改目标方法的执行结果;

@Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("执行了环绕通知 public Object myAround");
    System.out.println("目标方法之前执行");
    //执行目标方法
    Object methodReturn = pjp.proceed();//相当于method.invoke(),表示执行目标方法* *..AroundServiceImpl.do*(..)本身
    System.out.println("目标方法之后执行");
    //        return "Hello Around";//不是目标方法的执行结果
    return methodReturn;//返回目标方法的执行结果(没有修改的)
}

@Pointcut(value = "execution(* *..AroundServiceImpl.do*(..))")
public void myPointCut(){
    //无需代码
}

关于ProceedingJoinPoint 和JoinPoint:public interface ProceedingJoinPoint extends JoinPoint

5.5 @AfterThrowing

@AfterThrowing:异常通知。

 

 

 

版权声明:
作者:jackqiang
链接:http://www.jackqiang.com/framework/spring/2070/spring_anno/
来源:JackQiang's
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录