体验Java 1.5中面向(AOP)编程

下面是详细讲解“体验Java 1.5中面向(AOP)编程”的完整攻略。

下面是详细讲解“体验Java 1.5中面向(AOP)编程”的完整攻略。

背景

在Java 1.5中引入了注解和泛型等新特性,同时也提供了对面向切面编程(AOP)的支持,使得在Java中实现AOP变得更加容易和灵活。

AOP介绍

AOP是一种编程思想,将程序中的各种横向逻辑(如日志、权限控制、事务管理等)提取出来,形成切面,通过将切面和业务逻辑进行织入,实现了系统各个模块的解耦和复用。

在Java中实现AOP通常通过代理模式和拦截器来实现,Java 1.5提供了注解和反射机制,可以使得织入切面更加灵活和方便。

实现步骤

1. 定义切面注解

首先需要定义一个注解来标记切面。这个注解可以是一个空注解,在之后的使用中通过编写切面类并在类上添加该注解来对目标代码进行织入。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAspect {
}

2. 定义切点注解

接着需要定义切点的注解,切点就是表示哪些方法需要被织入切面。同样可以是一个空注解,只需要在目标方法上添加该注解即可。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyPointcut {
}

3. 定义切面类

定义一个切面类,在类上添加切面注解,同时定义织入目标代码前和织入目标代码后的处理方法,可以使用反射机制调用目标代码方法。

@MyAspect
public class LogAspect {
    @Before(myclz = UserService.class, mymethod = "login")
    public void before() {
        System.out.println("before login...");
    }

    @After(myclz = UserService.class, mymethod = "login")
    public void after() {
        System.out.println("after login...");
    }
}

在上面的例子中,使用了@Before@After注解分别表示在目标方法执行前和执行后要执行的方法。

4. 定义切面拦截器

继承MethodInterceptor类,实现其中的invoke方法,处理切面逻辑。

public class LogInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before " + method.getName() + "...");
        Object result = method.invoke(proxy, args);
        System.out.println("after " + method.getName() + "...");
        return result;
    }
}

5. 实现切面织入

使用Proxy类的newProxyInstance方法生成代理对象,织入定义好的切面。

public class UserServiceProxy {
    private UserService userService;

    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }

    public UserService getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new LogInterceptor());
        return (UserService) enhancer.create();
    }
}

在上面的例子中,使用了CGLib来生成代理对象,在代理对象中进行切面织入。

示例说明

下面提供两个示例来说明AOP的应用。

示例1

假设有一个用户管理系统,需要在登录成功的时候打印出登录日志。

首先定义一个切点注解@MyPointcut,标记需要织入切面的目标方法。

@MyPointcut
public boolean login(String username, String password) {
    //...
}

接着定义一个切面类LogAspect,使用@Before注解标记在目标方法执行之前需要执行的方法。

@MyAspect
public class LogAspect {
    @Before(myclz = UserService.class, mymethod = "login")
    public void before() {
        System.out.println("before login...");
    }
}

最后,在目标代码中使用AOP织入日志处理。

UserService userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
userService = userServiceProxy.getProxy();

userService.login("admin", "password");

在执行上面的代码之后,会先输出before login...,然后执行目标方法,最后输出after login...

示例2

假设有一个权限管理系统,需要在用户调用管理员操作时判断其是否有管理员权限。

首先定义一个切点注解@MyPointcut,标记需要织入切面的目标方法。

@MyPointcut
public void delete(String username) {
    //...
}

接着定义一个切面类AuthorityAspect,使用@Around注解标记在目标方法执行之前和执行之后需要执行的方法。

@MyAspect
public class AuthorityAspect {
    @Around(myclz = UserService.class, mymethod = "delete")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("before delete...");
        Object[] args = joinPoint.getArgs();
        String username = (String) args[0];
        if (userService.checkAuthority(username)) {
            joinPoint.proceed();
        } else {
            System.out.println("permission denied");
        }
        System.out.println("after delete...");
    }
}

在上面的例子中,使用了ProceedingJoinPoint对象获取切点方法参数,并使用proceed方法调用目标方法。

最后,在目标代码中使用AOP织入权限判断。

UserService userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
userService = userServiceProxy.getProxy();

userService.delete("admin");

在执行上面的代码之后,会先输出before delete...,接着判断权限并调用目标方法,如果有管理员权限则会输出删除成功,如果没有则会输出permission denied,最后输出after delete...

总结

通过上面的教程,我们了解了如何在Java 1.5中实现AOP,使用注解和反射机制可以使得AOP更加灵活和方便。在实际开发中,我们可以使用AOP来实现日志、权限控制、事务管理等横向逻辑,提高代码的复用性和可维护性。

本文标题为:体验Java 1.5中面向(AOP)编程

基础教程推荐