Spring AOP基于@AspectJ开发

准备POJO

package com.bob.analyst.admin.aop;

import org.springframework.stereotype.Component;

@Component
public class Role {
	private Long id;
	private String roleName;
	private String note;
	//setter and getter 省略
}

选择切点(Service和ServiceImpl)

Service:

package com.bob.analyst.admin.aop;
public interface RoleService {
	public void printRole(Role role);
}
ServiceImpl:

package com.bob.analyst.admin.aop;

import org.springframework.stereotype.Component;

@Component
public class RoleServiceImpl implements RoleService{
	@Override
	public void printRole(Role role) {
		System.out.println("{id:"+role.getId()+","
	+"role_name:"+role.getRoleName()+","
				+"note:"+role.getNote()+"}");
	}
}

创建切面

选择好切点就可以创建切面了,对于动态代理的概念而言,它就如同一个拦截器,在Spring中使用@Aspect注解一个类,那么Spring Ioc容器就会认为这是一个切面了。

package com.bob.analyst.admin.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class RoleAspect {

	/**
	 * execution 代表执行方法的时候会触发 * 代表任意返回类型的方法
	 * com.bob.analyst.service.impl.RoleServiceImpl 代表类的全限定名 printRole 被拦截方法名称
	 * (..) 任意的参数
	 */
	@Pointcut("execution(* com.bob.analyst.admin.aop.RoleServiceImpl.printRole(..))")
	public void print() {
	}
	
	// 前置通知
	// @Before("execution(*
	// com.bob.analyst.admin.aop.RoleServiceImpl.printRole(..))")
	@Before("print()")
	public void before() {
		System.out.println("before.....");
	}

	// 后置通知
	// @After("execution(*
	// com.bob.analyst.admin.aop.RoleServiceImpl.printRole(..))")
	@After("print()")
	public void after() {
		System.out.println("after.....");
	}

	// 返回通知(无异常)
	// @AfterReturning("execution(*
	// com.bob.analyst.admin.aop.RoleServiceImpl.printRole(..))")
	@AfterReturning("print()")
	public void afterReturning() {
		System.out.println("afterReturning.....");
	}

	// 异常通知
	// @AfterThrowing("execution(*
	// com.bob.analyst.admin.aop.RoleServiceImpl.printRole(..))")
	@AfterThrowing("print()")
	public void afterThrowing() {
		System.out.println("afterThrowing.....");
	}
}
连接点

在切面的类中每个方法上面的注解就是连接点的相关信息

测试AOP

即把之前的类注入到Spring Ioc容器中,然后运行


package com.bob.analyst.admin.aop;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.bob.analyst.admin.aop")
public class AopConfig {
	
	@Bean
	public RoleAspect getRoleAspect(){
		return new RoleAspect();
	}

}

package com.bob.analyst.admin.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
		RoleService roleService= (RoleService) ctx.getBean(RoleService.class);
		Role role = new Role();
		role.setId(1l);
		role.setRoleName("高级软件工程师");
		role.setNote("note_01");
		
		roleService.printRole(role);
		System.out.println("........................");
		role=null;
		roleService.printRole(role);
	}

}

结果:




环绕通知

环绕通知是Spring AOP中最强大的通知,它可以同时实现前置通知和后置通知。它保留了调度被代理对象原有方法的功能,所以它既强大又灵活。实现:在RoleAspect类中加入以下代码:

/**
	 * 环绕通知
	 * 
	 * @param jp
	 *            这个参数是Spring提供的,使用它可以反射切点方法。
	 */
	@Around("print()")
	public void around(ProceedingJoinPoint jp) {
		System.out.println("around before ....");
		try {
			jp.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("around after ....");
	}


在运行测试类main得出结果:



织入

织入是生成代理对象的过程,在上述的代码中,切点方法所在的类都是拥有接口的类,而事实上即使没有接口,Spring也能提供AOP的功能,所以是否拥有接口不是使用Spring AOP的一个强制要求,Spring提供了一个规则:当类的实现存在接口的时候,Spring将提供JDK动态代理,从而织入各个通知。而当类不存在接口的时候就没办法使用JDK动态代理,Spring会使用CGLIB来生成代理对象。备注:用Spring建议使用接口编程


引入

Spring AOP只是通过动态代理技术,把各类通过通知织入到它所约定的流程当中,而事实上,有时候我们希望引入其他类的方法来得到更好的实现,这时候就可以引入其他的方法了。先添加接口和实现:

package com.bob.analyst.admin.aop;

public interface RoleVerifier {
	public boolean verify(Role role);
}
package com.bob.analyst.admin.aop;

public class RoleVerifierImpl implements RoleVerifier {

	@Override
	public boolean verify(Role role) {
		System.out.println("验证Role是否为空........");
		return role != null;
	}
}

在RoleAspect类中添加

/**
	 * com.bob.analyst.admin.aop.RoleServiceImpl+ :
	 * 表示对RoleServiceImpl类进行增强,也就是在RoleServiceImpl中引入一个新的接口 defaultImpl :
	 * 代表其默认的实现类,这里是RoleVerifierImpl
	 */
	@DeclareParents(value = "com.bob.analyst.admin.aop.RoleServiceImpl+", defaultImpl = RoleVerifierImpl.class)
	public RoleVerifier roleVerifier;

更改测试


package com.bob.analyst.admin.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
		RoleService roleService= (RoleService) ctx.getBean(RoleService.class);
		
		/**
		 * 强制转换 把roleService转换为roleVerifier接口对象,然后就可以使用verify方法了。
		 * Spring AOP依赖于动态代理对象来实现,其代理对象可以挂在多个接口之下,只要Spring AOP让代理对象挂到RoleService 和 RoleVerifier
		 * 两个接口之下,那么就可以把对应的Bean通过强制转换,让其在这两个接口之间相互转换了。
		 */
		RoleVerifier roleVerifier = (RoleVerifier) roleService;
		Role role = new Role();
		role.setId(1l);
		role.setRoleName("高级软件工程师");
		role.setNote("note_01");
		if(roleVerifier.verify(role)){
			roleService.printRole(role);
		}
		System.out.println("........................");
		role=null;
		roleService.printRole(role);
	}
}


结果:




关于使用XML配置开发Spring AOP这里不再描述。。。













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值