spring03-aop
-
spring aop: 只能增强方法,,spring aop 底层是动态代理,,,动态代理的本质是生成一个子类,,重写这个方法,进行增强,,所以final修饰的类和方法,,或者是static静态方法,或者是private修饰的方法,都不能被继承,都会导致spring aop 失效
(图片来源网络,侵删) -
aspectJ aop: 能增强属性,类,静态方法,,等,是一个完整的,独立的,功能十分强大的aop解决方案,,是编译时增强,,性能也高于aop,,当然也支持运行时增强
spring aop 核心概念
- Target : 被拦截下来的对象(要被增强的对象)
- Join Point : 连接点,,, 可以被切面插入的地方
- Pointcut : 切点,, 被切面增强的连接点
- Advice: 通知,切点在连接处执行的代码,增强
- Aspect : 切面 , 通知和切点
- Weaving : 织入,,将切面应用到 Target的过程,,可以在编译的时候weaving,也可以在类加载的时候,,也可以在运行的时候,,织入
- introduction: 引介,,,,为某个类,增加新的方法或者属性,,,
aop的使用
定义一个增强:
public class CalculatorAdvice implements MethodBeforeAdvice { /** * * @param method 当前的方法 * @param args 方法参数 * @param target 当前对象 * @throws Throwable */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(method.getName()+" 开始执行。。。"); } }
xml中配置aop:
这个CalculatorImpl 的类被增强了,,产生了一个新的代理类,,这个容器里面的CalculatorImpl的bean,,被这个新的代理的bean替换掉了,,
public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); // 这里返回的是一个代理对象,,,并不是注入spring中的 ICalculator bean = ctx.getBean(ICalculator.class); // CalculatorImpl calculator = (CalculatorImpl) ctx.getBean("calculator"); // System.out.println("calculator = " + calculator); bean.add(1,2); bean.minus(1,2); }
另一种配置xml:
public class LogAdvice { public void before(JoinPoint jp){ // 方法名 String name = jp.getSignature().getName(); System.out.println(name+"开始执行。。"); } public void after(JoinPoint jp){ String name = jp.getSignature().getName(); System.out.println(name+"执行结束。。"); } public void exception(JoinPoint jp,Exception e){ String name = jp.getSignature().getName(); System.out.println(name+"异常。。"+e.getMessage()); } /** * 目标方法的返回值,,必须和这里的参数相匹配,,,该方法才会被触发 * @param jp * @param result */ public void returnAdvice(JoinPoint jp,int result){ String name = jp.getSignature().getName(); System.out.println(name+"返回值。。"+result); } public Object around(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); Object proceed = pjp.proceed(new Object[]{100,99}); long endTime = System.currentTimeMillis(); System.out.println(pjp.getSignature().getName()+"执行耗时"+(endTime-startTime)); return proceed; } }
java代码配置aop:使用自动扫描带@Aspect的切面
/** * * * aspect = pointcut + advice **/ @Aspect public class LogAspect { @Pointcut("execution(* com.cj.CalculatorImpl.*(..))") public void pc1(){} @Before("pc1()") public void before(JoinPoint jp){ // 方法名 String name = jp.getSignature().getName(); System.out.println(name+"开始执行。。"); } @After("pc1()") public void after(JoinPoint jp){ String name = jp.getSignature().getName(); System.out.println(name+"执行结束。。"); } @AfterThrowing(value = "pc1()",throwing = "e") public void exception(JoinPoint jp,Exception e){ String name = jp.getSignature().getName(); System.out.println(name+"异常。。"+e.getMessage()); } /** * 目标方法的返回值,,必须和这里的参数相匹配,,,该方法才会被触发 * @param jp * @param result */ @AfterReturning(value = "pc1()",returning = "result") public void returnAdvice(JoinPoint jp,int result){ String name = jp.getSignature().getName(); System.out.println(name+"返回值。。"+result); } @Around("pc1()") public Object around(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); Object proceed = pjp.proceed(new Object[]{100,99}); long endTime = System.currentTimeMillis(); System.out.println(pjp.getSignature().getName()+"执行耗时"+(endTime-startTime)); return proceed; } }
纯java类写法:
需要在切面上添加注解@EnableAspectJAutoProxy,这个注解是用来识别切面的,相当于在xml中配置
@Aspect @Component // 这个注解是用来识别切面的,,相当于 @EnableAspectJAutoProxy public class LogAspect { ... }
@Configuration @ComponentScan public class JavaConfig { }
spring aop 动态代理
如果有接口,用的jdk动态代理,,
没有接口,用的cglib动态代理
如果有接口,但是你不想使用jdk动态代理,而是使用cglib,,在@EnableAspectJAutoProxy 设置proxyTargetClass=true 就会使用cglib代理
spring aop拦截
- execution : 零侵入的拦截规则
- 注解
@annotation():方法上面有这个注解
@within() : 类上面有这个注解
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。