Spring开发_使用AOP

*AOP是一种新的编程方式,它和OOP不同,OOP把系统看作多个对象的交互,AOP把系统分解为不同的关注点,或者称之为切面(Aspect)。
*

AOP原理

**Spring的AOP实现是基于JVM的动态代理。**由于JVM的动态代理要求必须实现接口,如果一个普通类没有业务接口,就需要通过CGLIB或者Javassist这些第三方库实现。

装配AOP(使用AspectJ)

我们以UserService和MailService为例,这两个属于核心业务逻辑,现在,我们准备给UserService的每个业务方法执行前添加日志,给MailService的每个业务方法执行前后添加日志.

@Aspect
@Component
public class LoggingAspect{
	@Before("execution(public * com.itranswarp.learnjava.service.UserService.*(..))") 
	public void doAccessCheck() {
        System.err.println("[Before] do access check...");
    }
    @Around("execution(public * com.itranswarp.learnjava.service.MailService.*(..))")
    public Object doLogging(ProceedingJoinPoint pjp) throws Throwable {
        System.err.println("[Around] start " + pjp.getSignature());
        Object retVal = pjp.proceed();
        System.err.println("[Around] done " + pjp.getSignature());
        return retVal;
    }
}

在LoggingAspect类的声明处,除了用@Component表示它本身也是一个Bean外,我们再加上@Aspect注解,表示它的@Before标注的方法需要注入到UserService的每个public方法执行前,@Around标注的方法需要注入到MailService的每个public方法执行前后。

紧接着,我们需要给@Configuration类加上一个@EnableAspectJAutoProxy注解:

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class AppConfig {
    ...
}

如果我们想要把LoggingAspect.doAccessCheck()方法注入到UserService的每个public方法中,最简单的方法是编写一个子类:

public UserServiceAopProxy extends UserService{
	public UserService target;
	public LoggingAspect aspect;
	public UserServiceAopProxy(UserService target, LoggingAspect aspect){
		this.target = target;
		this.aspect = aspect;
	}
	public User login(String email, String password){
		aspect.doAccessCheck();
		return target.login(email, password);
	}
}

使用注解装配AOP

如果我们自己写的Bean希望在一个数据库事务中被调用,就标注上@Transactional:

@Component
public class UserService {
    // 有事务:
    @Transactional
    public User createUser(String name) {
        ...
    }

    // 无事务:
    public boolean isValidName(String name) {
        ...
    }

    // 有事务:
    @Transactional
    public void updateUser(User user) {
        ...
    }
}

演示如何使用注解实现AOP装配,我们定义一个性能监控的注解:

@Target(METHOD)
@Retention(RUNTIME)
public @interface MetricTime{
	String value();
}

在需要被监控的关键方法上标注该注解:

@Component
public class UserService{
	@MetricTime("register")
	public User register(String email, String password, String name){
	...}
}

然后,我们定义MetricAspect:

@Aspect 
@Component
public class MetricAspect{
	@Around("@annotation(metricTime)")
	public Object metric(ProceedingJoinPoint joinPoint, MetricTime metricTime) throws Throwable {
        String name = metricTime.value();
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed();
        } finally {
            long t = System.currentTimeMillis() - start;
            // 写入日志或发送至JMX:
            System.err.println("[Metrics] " + name + ": " + t + "ms");
        }
    }
}

注意metric()方法标注了@Around("@annotation(metricTime)"),它的意思是,符合条件的目标方法是带有@MetricTime注解的方法,因为metric()方法参数类型是MetricTime(注意参数名是metricTime不是MetricTime),我们通过它获取性能监控的名称。

有了@MetricTime注解,再配合MetricAspect,任何Bean,只要方法标注了@MetricTime注解,就可以自动实现性能监控。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值