spring AOP (包含基于注解和配置文件两种方式)

spring AOP?面向切面编程,区别于面向对象编程OOP

AspectJ: 是Java社区里面最完整最流行的AOP框架,下面就用aspectJ来上例子

一.基于注解方式

步骤如下:

  1. 引入jar包(spring的必要jar包 以及aspectj的jar包)
  2. 业务方法HelloworldService (类上加上注解@Component,放入到spring ioc容器中)
  3. 切面LogingAop (类上加上注解@Component使其加入到ioc容器中,还需要注解@Aspect,使其成为一个切面)
  4. spring配置文件applicationContext.xml (扫描包,以及aop生成代理类的配置<aop:aspectj-autoproxy/>)
  5. 测试

结构如下:

HelloworldService代码实现:

package com.aop.demo;

import org.springframework.stereotype.Component;

@Component
public class HelloworldService {

    public int add(int i, int j){
        return i+j;
    }
}

LogingAop代码实现:

package com.aop.demo;

import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogingAop {

    @Pointcut("execution(public int com.aop.demo.HelloworldService.add (int,int))")
    public void pointcut(){};

    @Before(value="pointcut()")
    public void beforeMethod(JoinPoint jointPoint){
        String methodName = jointPoint.getSignature().getName();
        List args = Arrays.asList(jointPoint.getArgs());
        System.out.println("Method("+methodName+") args("+args+") Start");
    }
}

applicationContext.xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

<context:component-scan base-package="com.aop.demo"></context:component-scan>
<aop:aspectj-autoproxy/>
</beans>

测试代码如下

package com.aop.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloworldService helloworldService = (HelloworldService) ctx.getBean("helloworldService");
        int result = helloworldService.add(1, 2);
        System.out.println("Result is "+result);
    }
}

测试结果如下:

Method(add) args([1, 2]) Start
Result is 3

 AOP中的概念介绍:

切面:跨越应用程序多个模块的功能,比如打日志,比如参数验证,类似这种被模块化的特殊对象
通知: 上面切面中的方法
切入点:相当于查询条件,在哪些业务方法中需要加入通知,spring自动生成新的代理对象

 AspectJ支持5中类型的通知注解:

@Before: 前置通知,在方法执行之前执行
@After: 后置通知,在方法执行之后执行 (不管是否有异常,都会执行)
@AfterRuning: 返回通知,在方法返回结果之后执行 (只在没有异常时候才执行)
@AfterThrowing: 异常通知,在方法抛出异常之后
@Around: 环绕通知,围绕着方法执行

AspectJ的5中注解的代码示例

package com.aop.demo;

import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
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.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogingAop {

    @Pointcut("execution(public int com.aop.demo.HelloworldService.add (int,int))")
    public void pointcut(){};

    @Before(value="pointcut()")
    public void beforeMethod(JoinPoint jointPoint){
        String methodName = jointPoint.getSignature().getName();
        List args = Arrays.asList(jointPoint.getArgs());
        System.out.println("Method("+methodName+") args("+args+") Start");
    }

    @After(value="pointcut()")
    public void afterMethod(JoinPoint jointPoint){
        String methodName = jointPoint.getSignature().getName();
        List args = Arrays.asList(jointPoint.getArgs());
        System.out.println("Method("+methodName+") args("+args+") After");
    }

    @AfterReturning(value="pointcut()",returning="result")
    public void afterReturingMethod(JoinPoint jointPoint,Object result){
        String methodName = jointPoint.getSignature().getName();
        List args = Arrays.asList(jointPoint.getArgs());
        System.out.println("Method("+methodName+") args("+args+") After Runing + Result:"+result);
    }

    @AfterThrowing(value="pointcut()",throwing="e")
    public void afterThrowingMethod(JoinPoint jointPoint,Exception e){
        String methodName = jointPoint.getSignature().getName();
        List args = Arrays.asList(jointPoint.getArgs());
        System.out.println("Method("+methodName+") args("+args+") After Throw Exception:" +e);
    }

    @Around(value="pointcut()")
    public Object aroundMethod(ProceedingJoinPoint jointPoint){

        Object result = null;
        String methodName = jointPoint.getSignature().getName();
        try {
            System.out.println(methodName+"前置通知.....");
            result = jointPoint.proceed();
            System.out.println("后置通知.....");
        } catch (Throwable e) {
            System.out.println("异常通知.....");
            throw new RuntimeException();
        }
        System.out.println("返回通知.....");
        return result;
    }
}

注意:@Around环绕通知,必须携带对象ProceedingJoinPoint参数

环绕通知类似于动态代理的全部过程,可以决定是否执行目标方法

 切面的优先级

可以在切面上注解@Order,其中值越小,切面的优先级越高

二.基于配置文件方式

步骤如下:

  1. 将上面的三个类移到其他包里面,去掉类以及方法中的所有注解
  2. 定义新的配置文件applicationContext-xml.xml

结构如下:

applicationContext-xml.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

    <!-- 配置业务bean -->
    <bean id="helloworldService" class="com.aop.demo.xml.HelloworldService"></bean>

    <!-- 配置切面 -->
    <bean id="logingAop" class="com.aop.demo.xml.LogingAop"></bean>

    <!-- 配置AOP -->
    <aop:config>
        <aop:pointcut
            expression="execution(public int com.aop.demo.xml.HelloworldService.add (int,int))" id="pointCut" />
        <aop:aspect ref="logingAop">
            <aop:before method="beforeMethod" pointcut-ref="pointCut" />
        </aop:aspect>
    </aop:config>

</beans>
时间: 2024-07-31 14:22:44

spring AOP (包含基于注解和配置文件两种方式)的相关文章

org.apache.hadoop.yarn.conf.ConfigurationProviderFactory分析加载配置文件两种方式

ConfigurationProviderFactory结构如下: /** * Creates an instance of {@link ConfigurationProvider} using given * configuration. * @param bootstrapConf * @return configurationProvider */ @SuppressWarnings("unchecked") public static ConfigurationProvide

不使用spring的情况下原生java代码两种方式操作mongodb数据库

由于更改了mongodb3.0数据库的密码,导致这几天storm组对数据进行处理的时候,一直在报mongodb数据库连接不上的异常.   主要原因实际上是和mongodb本身无关的,因为他们改的是配置文件的密码,而实际上这个密码在代码中根本就没有使用,他们在代码中已经把用户验证信息写死.   在协助他们解决这个问题的时候,我看到他们代码中在和mongodb数据库交互时使用了已经不被建议使用的方法,于是便抽时间尝试了一下另一种被建议的方式实现各功能.   当然了,生产环境中用的是mongodb集群

Spring中使用quartz执行定时任务的两种方式

一, 继承spring封装Quartz类(org.springframework.scheduling.quartz.QuartzJobBean)方式 spring-mvc-quartz2.xml: <bean id="job2Trigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail">

Spring中使用属性文件properties的两种方式

实际项目中,通常将可配置的参数放到属性文件中,例如数据库连接信息.redis连接信息等,便于统一管理.然后通过IoC框架spring将其加载到上下文中,使得程序可以直接使用. 创建mysql.properties文件,并置于CLASSPATH路径中,如果使用maven构建工程,直接放置在resources文件夹下.文件内容: mysql.url=jdbc:mysql://192.168.1.101:3306/demo mysql.username=rootmysql.password=12345

Spark基于Yarn提交任务两种方式

yarn-client提交任务方式 客户端提交一个Application,在客户端启动一个Driver进程 Driver进程会向RS(ResourceManager)发送请求,启动AM(ApplicationMaster)的资源 RS收到请求,随机选择一台NM(NodeManager)启动AM.这里的NM相当于Standalone中的Worker节点 AM启动后,会向RS请求一批container资源,用于启动Executor RS会找到一批NM返回给AM,用于启动Executor AM会向NM

.Spark基于Standalone提交任务两种方式

Standalone-client模式: 1.client模式提交任务后,会在客户端启动Driver进程2.Driver会向Master申请启动Application启动的资源3.资源申请成功,Driver端将task发送到worker端执行4.worker将task执行结果返回到Driver端   Standalone-master模式: 1.cluster模式提交应用程序后,会向Master请求启动Driver.(而不是启动application)2.Master接受请求,随机在集群一台节点

Java连接Neo4j的两种方式

1.Neo4j数据库的两种方式 Neo4j可以以两种方式运行: Java应用程序中的嵌入式数据库 通过REST的独立服务器 不管哪一种方式,这个选择不会影响查询和使用数据库的方式. 它是由应用程序的性质(无论是独立服务器还是客户端服务器),性能,监视和数据安全性驱动的架构选择. 1.1Neo4j Server(服务器式数据库) Neo4j Server是互操作性,安全性和监控的最佳选择. 实际上,REST接口允许所有现代平台和编程语言与它进行互操作. 此外,作为独立应用程序,它比嵌入式配置更安全

使用 Spring 2.5 基于注解驱动的 Spring MVC--转

概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Spring 2.5 又为 Spring MVC 引入了注解驱动功能.现在你无须让 Controller 继承任何接口,无需在 XML 配置文件中定义请求和 Controller 的映射关系,仅仅使用注解就可以让一个 POJO 具有 Controller 的绝大部分功能 —— Spring MVC 框架的易用性得到了进一步的增强.在框架灵活性.易用性和扩展性上,Spring MVC 已经全面超越了其它的 MVC 框架,伴随

spring学习2:基于注解+xml实现ioc和依赖注入

spring学习2:基于注解+xml实现ioc和依赖注入 一.在spring配置文件中开启spring对注解的支持 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&qu