spring aop advice

本文内容纲要:spring aop advice

1.前置通知(BeforeAdvice):

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class HelloBeforeAdvice implements MethodBeforeAdvice{

public void before(Method method, Object[] args, Object target) throws Throwable {

System.out.println("do something before some method");

}

}

如果出现 The hierarchy of the type HelloBeforeAdvice is inconsistent错误 , 是缺少相关的jar或者jdk环境不对。

2.后置通知(AfterAdvice)

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class HelloAfterAdvice implements AfterReturningAdvice {

public void afterReturning(Object result, Method method, Object[] args, Object target) throws Throwable {

System.out.println("do something after the method");

}

}

  1. Test client

    import org.springframework.aop.framework.ProxyFactory;

    public class TestClient {

     public static void main(String[] args) {

    ProxyFactory proxyFactory = new ProxyFactory();//创建代理工厂

    proxyFactory.setTarget(new HelloImpl());

    proxyFactory.addAdvice(new HelloBeforeAdvice());

    proxyFactory.addAdvice(new HelloAfterAdvice());

    Hello helloProxy = (Hello) proxyFactory.getProxy();

    System.out.println(helloProxy.sayHello("zhangsan"));

    }

    }


    public class HelloImpl implements Hello {

        public String sayHello(String str) {

            System.out.println("hello>>>"+str);

            return "hello>>>"+str;

        }

    }

  2. 环绕通知(AroundAdvice)

    //aop联盟提供的接口

    import org.aopalliance.intercept.MethodInterceptor;

    import org.aopalliance.intercept.MethodInvocation;

    public class HelloAroundAdvice implements MethodInterceptor {

     public Object invoke(MethodInvocation invocation) throws Throwable {

    System.out.println("before method>>>");

    Object result = invocation.proceed();

    System.out.println("after method>>");

    return result;

    }

    }

  3. spring 配置文件方式

     <context:component-scan base-package="com.cdv.ppms"></context:component-scan>

    <bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="interfaces" value="com.cdv.ppms.Hello"/><!-- 需要代理的接口 -->

    <property name="target" ref="helloImpl"/><!-- 接口实现类 , 此处需要是ref 否则object is not an instance of declaring class-->

    <property name="interceptorNames"><!-- 拦截器 名称-->

    <list>

    <value>helloAroundAdvice</value>

    </list>

    </property>

    </bean>

       

    import org.springframework.stereotype.Component;

    @Component

    public class HelloImpl implements Hello {

    //...

    }

    @Component

    public class HelloAroundAdvice implements MethodInterceptor {

    //....

    }

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class TestXMLClient {

     public static void main(String[] args) {

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

    Hello hello = (Hello) context.getBean("helloProxy");

    hello.sayHello("test xml");

    }

    }

  4. 抛出通知(ThrowAdvice)

    import java.lang.reflect.Method;

    import org.springframework.aop.ThrowsAdvice;

    import org.springframework.stereotype.Component;

    @Component

    public class HelloThrowAdvice implements ThrowsAdvice{

    public void afterThrowing(Method method, Object[] args, Object target, Exception e){

    System.out.println("-------------------Throw Exception------------------------");

    System.out.println("target class>>"+target.getClass().getName());

    System.out.println("method class>>" + method.getName());

    System.out.println("exception message>>"+e.getMessage());

    System.out.println("-------------------Throw Exception------------------------");

    }

    }

    helloAroundAdvice

    testThrowAdvice

    import org.springframework.stereotype.Component;

    @Component

    public class HelloImpl implements Hello {

     public String sayHello(String str) {

    System.out.println("hello>>>"+str);

    throw new RuntimeException("error>>");//加入异常以便测试

    }

    }

  5. 引入通知(Introduction Advice)

对方法的增强叫织入(Weaving),对类的增强叫引入(Introduction)

import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.support.DelegatingIntroductionInterceptor;

import org.springframework.stereotype.Component;

@Component

public class HelloIntroAdvice extends DelegatingIntroductionInterceptor implements Apology {

/**

*

*/

private static final long serialVersionUID = -3328637206414010549L;

public Object invoke(MethodInvocation invocation) throws Throwable{

return super.invoke(invocation);

}

public void saySorry(String str) {

System.out.println("introduction advice>>>"+str);

}

}

<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="interfaces" value="com.cdv.ppms.Apology"/><!-- 需要代理的接口 -->

<property name="target" ref="helloImpl"/><!-- 接口实现类 -->

<property name="interceptorNames"><!-- 拦截器 名称-->

<list>

<value>helloAroundAdvice</value>

<value>helloThrowAdvice</value>

<value>helloIntroAdvice</value>

</list>

</property>

<property name="proxyTargetClass" value="true"></property><!--代理目标类, 默认false代理接口-->

</bean>

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloProxy");

helloImpl.sayHello("test xml");

Apology apology = (Apology) helloImpl;//将目标类向上强制转型为Apology接口, 这时引入通知给我们带来的特性, 也就是“接口动态实现”功能

apology.saySorry("zhangsan");

}

}

  1. 切面(Advisor)

切面(Advisor)封装了通知(Advice)和切点(Pointcut)

import org.springframework.stereotype.Component;

@Component

public class HelloImpl implements Hello {

public String sayHello(String str) {

System.out.println("hello>>>"+str);

return str;

}

public void advisorOne(String name){

System.out.println("advisor one>>>"+name);

}

public void advisorTwo(String name){

System.out.println("advisor two>>"+name);

}

}

在代理类中新增以advisor开头的方法,对其进行拦截

<context:component-scan base-package="com.cdv.ppms"></context:component-scan>

    <!--定义切面-->

<bean id="helloAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

<property name="advice" ref="helloAroundAdvice"/>

<property name="pattern" value="com.cdv.ppms.HelloImpl.advisor.*"></property><!-- 切点 (正则表达式) -->

</bean>

<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="target" ref="helloImpl"/><!-- 接口实现类 -->

<property name="interceptorNames" value="helloAdvisor"/>

<property name="proxyTargetClass" value="true"></property>

</bean>

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

<bean id="helloAroundAdvice" class="com.cdv.ppms.HelloAroundAdvice"></bean>

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;

import org.springframework.stereotype.Component;

@Component

public class HelloAroundAdvice implements MethodInterceptor {

public Object invoke(MethodInvocation invocation) throws Throwable {

System.out.println("before method>>>");

Object result = invocation.proceed();

System.out.println("after method>>");

return result;

}

}

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloProxy");

helloImpl.advisorOne("11111111");

helloImpl.advisorTwo("2222222222");

}

}

-------------around包了两层, 有问题-------------------------------------------

before method>>>

before method>>>

advisor one>>>11111111

after method>>

after method>>

before method>>>

before method>>>

advisor two>>2222222222

after method>>

after method>>

------------------------

随着项目的扩大, 上述的代理配置会越来越多。

  1. 自动代理(扫描bean名称)

定义BeanNameAutoProxyCreator,该bean是个bean后处理器,无需被引用,因此没有id属性

<context:component-scan base-package="com.cdv.ppms"></context:component-scan>

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="beanNames" value="*Impl"/><!--对以Impl结尾的类进行处理-->

<property name="interceptorNames" value="helloAroundAdvice"/>

<property name="optimize" value="true"/>

</bean>

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

<bean id="helloAroundAdvice" class="com.cdv.ppms.HelloAroundAdvice"></bean>

测试

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");

helloImpl.advisorOne("11111111");//

helloImpl.advisorTwo("2222222222");

helloImpl.sayHello("zhangwuji");

}

}

  1. 自动代理(扫描切面配置)

代理将由DefaultAdvisorAutoProxyCreator自动生成,这个类可以扫描所有的切面类

<context:component-scan base-package="com.cdv.ppms"></context:component-scan>

<bean id="helloAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

<property name="advice" ref="helloAroundAdvice"/>

<property name="pattern" value="com.cdv.ppms.HelloImpl.advisor.*"/>

</bean>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">

<property name="optimize" value="true"/>

</bean>

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

<bean id="helloAroundAdvice" class="com.cdv.ppms.HelloAroundAdvice"></bean>

测试

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");

helloImpl.advisorOne("11111111");

helloImpl.advisorTwo("2222222222");

helloImpl.sayHello("zhangwuji");

}

}

//只有符合advisor开头的方法才会被代理

这样在spring的配置中会存在大量的切面配置(想拦截指定注解的方法,就必须拓展DefaultPointcutAdvisor类,自定义一个切面类)。

  1. Spring & AspectJ

11-1 基于注解 :通过execution()表达式 拦截方法

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class HelloAspect {

@Around("execution(* com.cdv.ppms.HelloImpl.*(..))")//切点表达式

public Object around(ProceedingJoinPoint pjp) throws Throwable{

before();

Object result = pjp.proceed();

after();

return result;

}

private void after() {

System.out.println("hey,, after.");

}

private void before() {

System.out.println("hey,, before");

}

}

切点表达式

execution()表示拦截的方法, 挂号中定义拦截的规则

上面第一个*表示返回任意类型

第二个*表示HelloImpl类中的任意方法

..表示任意类型参数

<context:component-scan base-package="com.cdv.ppms"></context:component-scan>

<aop:aspectj-autoproxy proxy-target-class="true"/><!-- 默认值为false只能代理接口,当为true时才能代理目标类 -->

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

test

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");

helloImpl.advisorOne("11111111");

helloImpl.advisorTwo("2222222222");

helloImpl.sayHello("zhangwuji");

}

}

11-2 基于注解 通过AspectJ @annotation表达式拦截方法

自定义注解

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface MyTag {

}

更改aspect类的切点表达式

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class HelloAspect {

@Around("@annotation(com.cdv.ppms.MyTag)")

public Object around(ProceedingJoinPoint pjp) throws Throwable{

before();

Object result = pjp.proceed();

after();

return result;

}

private void after() {

System.out.println("hey,, after.");

}

private void before() {

System.out.println("hey,, before");

}

}

该注解可以标注在方法上,运行时生效

import org.springframework.stereotype.Component;

@Component

public class HelloImpl implements Hello {

public String sayHello(String str) {

System.out.println("hello>>>"+str);

return str;

}

@MyTag

public void advisorOne(String name){

System.out.println("advisor one>>>"+name);

}

public void advisorTwo(String name){

System.out.println("advisor two>>"+name);

}

}

配置

<context:component-scan base-package="com.cdv.ppms"></context:component-scan>

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

测试

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");

helloImpl.advisorOne("11111111");

helloImpl.advisorTwo("2222222222");

helloImpl.sayHello("zhangwuji");

}

}

其他几个注解

@Before @After @AfterThrowing @DeclareParents引入通知 AfterReturning(返回后通知,在方法结束后执行)

11-3 引入通知

Aspect类

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.DeclareParents;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class HelloAspect {

    //something need to do

@DeclareParents(value="com.cdv.ppms.HelloImpl",defaultImpl=com.cdv.ppms.ApologyImpl.class)

private Apology apology;

}

接口实现类

public class ApologyImpl implements Apology {

public void saySorry(String str) {

System.out.println("apologyImpl>>>"+str);

}

}

配置

<context:component-scan base-package="com.cdv.ppms"></context:component-scan>

<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>

测试

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXMLClient {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");

helloImpl.sayHello("zhangwuji");

Apology apology = (Apology) helloImpl;

apology.saySorry("hahahahah");

}

}

本文内容总结:spring aop advice

原文链接:https://www.cnblogs.com/rocky-fang/p/5459346.html

以上是 spring aop advice 的全部内容, 来源链接: utcz.com/z/362907.html

回到顶部