Spring AOP实现:面向切面编程——动态代理原理

1.  Aop—–面向切面编程:原理动态代理

1、 aop在spring中的作用

a)    提供声明式事务

b)    允许用户自定义切面,在不改变原有功能的前提下,添加新的功能。

2、 名词解释

a)    关注点:增加的某个业务。如添加日志,事务等功能。

b)    切面(aspect)一个关注点的模块化。

c)     通知(advice)在切面的某个特定的连接点上执行的动作。

d)    织入:把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。

3、 常用通知类型

a)    前置通知:MethodBeforeAdvice

b)    后置通知:AfterReturningAdvice

c)     环绕通知:MethodInterceptor

d)    异常通知:ThrowsAdvice,通常使用pojo方式来实现!

4、 spring提供实现aop的两种方式:

a)    依赖接口方式

                i.         第一步导入aop相应的jar包。

               ii.         定义一个接口

              iii.         添加配置文件:配置文件要添加aop的命名空间

             iv.         添加aop标签:使用<aop:config>

              v.         因为aop实现原理是动态代理:

Exception in thread “main” org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named ‘userDao’ must be of type [com.bjsxt.dao.impl.UserDaoImpl], but was actually of type [com.sun.proxy.$Proxy2]
解决方案:使用接口去接收。。。。。。。。。

             vi.         前置通知

public class Before implements MethodBeforeAdvice {

 

         /**

          * method:方法名

          * args:参数列表

          * target:目标对象

          */

         @Override

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

                   if (args.length!=0) {

                            for (int i = 0; i < args.length; i++) {

                                     System.out.println(method + “\t” + args[i] +“\t” + target.toString()+“\t”);

                            }

                   }

                   System.out.println(method + “\t” + args +“\t” + target.toString()+“\t”);

                   System.out.println(前置通知!”);

         }

}

<!– 要实现调dao层的方法就会打印出前置通知! –>

<bean id=“userDao” class=“com.bjsxt.dao.impl.UserDaoImpl”></bean>

 

<!– 定义前置通知 –>

<bean id=“before” class=“com.bjsxt.advice.Before”></bean>

<!– aop的配置 –>      

<aop:config>

         <!– 切入点:

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

                   第一个*后面代表包的路径

                   第二个*代表包内的任意类

                   第三个*代表保内的任意方法

                   (..):代表方法中的任意参数

                  

         –>

         <aop:pointcut expression=“execution(* com.bjsxt.dao.impl.*.*(..))” id=“mypoint”/>

                   <!– advice-ref:指的是配置那个通知 pointcutref:切入点的Id –>

                   <aop:advisor advice-ref=“before” pointcut-ref=“mypoint”/>

</aop:config>

</beans>

            vii.         测试:

public static void main(String[] args) {

                   ApplicationContext ac = new ClassPathXmlApplicationContext(“spring.xml”);

                   UserDao daoImpl = ac.getBean(“userDao”,UserDao.class);

                   daoImpl.delete(12);

                   daoImpl.add();

         }

注意该地方使用的是UserDao接口

           viii.         后置通知

public class After implements AfterReturningAdvice{

         /**

          * returnValue:返回值

          * method:方法名

          * args:参数列表

          * target:目标对象

          */

         @Override

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

                   System.out.println(returnValue);

                   System.out.println(后置通知!”);

         }

}

<!– aop的配置 –>  

<aop:config>

        <aop:pointcut expression=“execution(* com.bjsxt.dao.impl.*.*(..))” id=“mypoint”/>

        <!– advice-ref:指的是配置那个通知 pointcutref:切入点的Id –>

        <aop:advisor advice-ref=“before” pointcut-ref=“mypoint”/>

        <aop:advisor advice-ref=“after” pointcut-ref=“mypoint”/>

</aop:config>

             ix.         环绕通知:环绕通知-类似于前置通知,后置通知。  环绕通知的功能,相当于前置通知+后置通知!在实际开发过程中:要不采用环绕通知,要不采用前置通知+后置通知。

b)    Pojo方式(AspectJ)

                i.         先创建一个类:

public class Log {

         public void before(){

                   System.out.println(方法执行前”);

         }

        

         public void after(){

                   System.out.println(方法执行后!”);

         }

        

         public void ex(Exception e) throws Exception{

                   System.out.println(异常通知!”+e.getMessage());

         }

        

         public Object around(ProceedingJoinPoint p) throws Throwable{

                   System.out.println(环绕通知前!”);

                   Object obj = p.proceed();

                   System.out.println(环绕通知后!”);

                   return obj;

         }

}

               ii.         Spring.xml

<!– 使用pojo方式来实现aop –>

<bean id=“log” class=“com.bjsxt.advice.Log”></bean>

<aop:config>

         <aop:pointcut expression=”execution(* com.bjsxt.dao.impl.*.*(..))” id=”mypoint“/>

                   <aop:aspect ref=”log”>

                            <aop:before method=”before” pointcutref=”mypoint“/>

                            <aop:after method=”after” pointcutref=”mypoint“/>

                            <aop:around method=”around” pointcutref=”mypoint“/>

<aop:after-throwing method=”ex” pointcut-ref=”mypoint” throwing=”e”/>

                   </aop:aspect>

</aop:config>

c)     注解方式实现aop

@Aspect

public class Logs {

       @Before(“execution(* com.bjsxt.dao.impl.*.*(..))”)

       public void before(){

              System.out.println(方法执行前!”);

       }

       @After(“execution(* com.bjsxt.dao.impl.*.*(..))”)

       public void after(){

              System.out.println(方法执行后”);

       }

       @Around(“execution(* com.bjsxt.dao.impl.*.*(..))”)

       public Object around(ProceedingJoinPoint p) throws Throwable{

              System.out.println(环绕通知前!”);

              Object obj = p.proceed();

              System.out.println(环绕通知后!”);

              return obj;

       }

}

d)    Spring.xml

<!– 使用注解方式来实现aop –>

<bean id=“logs” class=“com.bjsxt.advice.Logs”></bean>

<!– aop的配置 –>   

<aop:aspectj-autoproxy/>

    原文作者:AOP
    原文地址: https://blog.csdn.net/m_q_x/article/details/77892544
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞