SpringAOP切面编程

1.AOP

AOP全称是Aspect-Oriented Programming,面向切面编程(面向方面编程)。它是面向对象编程(OOP)的一种补充。

2.AOP简介

传统业务处理代码中,会进行事务处理,日志记录等,用OOP可以通过组合或继承方式达到代码重用,但要实现某个功能,同样的代码会分散到各个方法中,这样要关闭某个功能,或修改,就要修改所有相关方法,提高了工作量和出错率。
AOP思想产生,采用横向抽取机制,将分散再各个方法中的重复代码提取出来,在程序编译或运行时,在运用到需要执行的地方,传统的OOP只能实现父子关系的纵向重用。AOP是OOP的延伸和补充。
AOP切面

3.SpringAOP简介

1.类与切面的关系

类与切面
AOP的使用,使开发人员在编写业务逻辑时可以专心去核心业务,不用过多的关注于其它业务逻辑的实现,不但提高了开发效率,而且增强了代码的可维护性。

2.AOP术语

图
Proxy(代理):将通过应用到目标对象之后,被动态创建的对象。
Weaving(织入):将切面代码插入到目标对象上,从而形成代理对象的过程。
Advice(通知/增强处理):AOP框架在特定的切入点执行的增强处理,即在定义好的切入点除所要执行的程序代码,可以将其理解为切面类中的方法。
Target Object(目标对象):指所有被通知的对象,也被称为被增强对象。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理对象。
Aspect(切面):封装的用于横向插入系统功能(如事务、日志等)的类
Joinpoint(连接点):在程序执行过程中的某个阶段点
Pointcut(切入点):切面与程序流程的交叉点,即那些需要处理的连接点

4.动态代理的两种基本实现

1.JDK动态代理
JDK动态代理是通过
java.lang.reflect.Proxy
类来实现的,我们可以调用Proxy类的
newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。
2.CGLIB代理
JDK动态代理用起来很简单,但是有局限性,用动态代理对象必须实现一个或多个接口,为了实现类的代理可以使用CGLIB代理。
CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它采用非常底层的字节码技
术,对指定的目标类生成一个子类,并对子类进行增强。

5.基于ProxyFactoryBean代理的实现

1.ProxyFactoryBean

ProxyFactoryBean是FactoryBean接口的实现类,FactoryBean负责实例化一个Bean,而ProxyFactoryBean负责为其他Bean创建代理实例,在Spring中使用ProxyFactoryBean是创建AOP代理的基本方式
可以配置的属性

2.实现

引入依赖


<properties> <!--在当前pom 或者父类pom 中声明属性 --> <spirng.version>5.0.16.RELEASE</spirng.version> 
</properties> 
<dependencies> 
	<dependency> 
		<groupId>org.springframework</groupId> 				
		<artifactId>spring-context</artifactId> 
		<version>${spirng.version}</version> 
	</dependency> 
	<!-- 导入spring aop --> 
	<dependency> 	
		<groupId>org.springframework</groupId>
		<artifactId>spring-aop</artifactId> 
		<version>${spirng.version}</version> 			
	</dependency> 
</dependencies> 

实体类Student

public class Student {
    private int id;
    private String name;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

抽象类StuentDao

import entity.Student;

public interface StudentDao {
    Student findStudentById(int id);
}

StudentDaoImpl

import dao.StudentDao;
import entity.Student;
import org.springframework.stereotype.Repository;

@Repository
public class StudentDaoImpl implements StudentDao {
    public Student findStudentById(int id) {
        Student student=new Student();
        student.setId(id);
        student.setName("小刘");
        return student;
    }
}

MyAspect

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAspect implements MethodInterceptor {
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        log(methodInvocation.getMethod().getName());
        Object object=methodInvocation.proceed();
        return object;
    }
    public void log(String log){
        System.out.println("日志调用方法:"+log);
    }
}

aop.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: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 https://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="studentDao" class="dao.impl.StudentDaoImpl"></bean>
    <bean id="myAspect" class="aop.MyAspect"></bean>
    <bean id="factoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="studentDao"></property>
        <property name="interceptorNames" value="myAspect"></property>
        <property name="proxyTargetClass" value="false"></property>
    </bean>
</beans>

test

import dao.StudentDao;
import entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("aop/aop.xml");
        StudentDao studentDao=(StudentDao) applicationContext.getBean("factoryBean");
        Student student=studentDao.findStudentById(1);
        System.out.println(student);
    }
}

6.基于Aspectj开发的实现

Aspectj是一个基于java语言的AOP框架,提供了强大的AOP功能。
使用Aspectj实现AOP两种方式:
1.基于XML的声明Aspectj
2.基于注解声明Aspectj

1.spring通知的类型

Spring按照通知在目标类方法的连接点位置,可以分为5种类型,具体如下:
1.org.springframework.aop.MethodBeforeAdvice(前置通知)在目标方法执行前实施增强,可以应用于权限管理等功能。
2.org.springframework.aop.AfterReturningAdvice(后置通知) 在目标方法执行后实施增强,可以应用于关闭流、上传文件、删除
临时文件等功能。
3.org.aopalliance.intercept.MethodInterceptor(环绕通知)在目标方法执行前后实施增强,可以应用于日志、事务管理等功能。
4.org.springframework.aop.ThrowsAdvice(异常抛出通知)在方法抛出异常后实施增强,可以应用于处理异常记录日志等功能。
5.org.springframework.aop.IntroductionInterceptor(引介通知)在目标类中添加一些新的方法和属性,可以应用于修改老版本程序。

2.基于XML的声明式Aspectj

基于xml声明式Aspectj是通过XML文件来定义切面,切入点及通知,所有的切面,切入点和通知都必须定义在aop:config元素内。

配置切面
在Spring的配置文件中,配置切面使用的是aop:aspect元素,该元素会将一个已定义好的springBean转化称切面Bean,所以要在配置文件中先定义一个普通的SpringBean。

<aop:config>
	<aop:aspect ref="切面">
	...
	</aop:aspect>
</aop:config>

配置切入点:
当aop:pointcut元素作为aop:confifig元素的子元素定义时,表示该切入点是全局切入点,它可被多个切面所共享;当aop:pointcut元素作为aop:aspect元素的子元素时,表示该切入点只对当前切面有效。

<aop:pointcut id="切点名字" expression="execution(* 路径.*.*(..))"/>

切点表达式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) execution(权限修饰符? 返回值类型 方法类的全路径名?方法名(参数名)异常类型? )

配置通知:
使用aop:aspect子元素可以配置5种常用通知,这五个子元素不支持使用子元素,但在使用同时可以指定一些属性。
五种子元素
代码:
依赖

<properties> <!--在当前pom 或者父类pom 中声明属性 -->
    <spirng.version>5.0.16.RELEASE</spirng.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spirng.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>jsr250-api</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.12</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.12</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2</version>
    </dependency>
</dependencies>

dao层接口

package com.aaa.dao;

public interface InsuranceService {
    String buyInsurance();
}

impl实现

package com.aaa.dao.impl;

import com.aaa.dao.InsuranceService;
import org.springframework.stereotype.Repository;


@Repository
public class PICC implements InsuranceService {
    @Override
    public String buyInsurance() {
        return "卖票";
    }
}

切面

package com.aaa.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspectj {
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知"+joinPoint.getSignature().getName());
    }
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最终通知"+joinPoint.getSignature().getName());
    }
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知开启"+proceedingJoinPoint.getSignature().getName());
        Object result=proceedingJoinPoint.proceed();
        System.out.println("环绕通知关闭"+proceedingJoinPoint.getSignature().getName());
        return result;
    }
    public void myAfterReturning(JoinPoint joinPoint,Object result){
        System.out.println("后置通知"+joinPoint.getSignature().getName());
        System.out.println("result:"+result);
    }
    public void myThrow(JoinPoint joinPoint,Throwable e){
        System.out.println("异常通知:"+joinPoint.getSignature().getName()+"message"+e.getMessage());
    }
}

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <bean id="InsuranceService" class="com.aaa.dao.impl.PICC"/>
    <bean id="aspectj" class="com.aaa.aspectj.MyAspectj"/>
    <aop:config>
        <aop:aspect ref="aspectj">
            <aop:pointcut id="myPointCut" expression="execution(* com.aaa.dao.impl.*.*(..))"/>
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            <aop:around method="myAround" pointcut-ref="myPointCut"/>
            <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="result"/>
            <aop:after-throwing method="myThrow" pointcut-ref="myPointCut" throwing="e"/>
        </aop:aspect>
    </aop:config>
</beans>

测试

package com.aaa.aspectj;

import com.aaa.dao.InsuranceService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyAspectjTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("aspectj/aspectj.xml");
        InsuranceService insuranceService=applicationContext.getBean(InsuranceService.class);
        String string=insuranceService.buyInsurance();
        System.out.println(string);
    }
}

基于注解的Aspectj

Aspectj注解
代码
切面:

package com.aaa.aspectjAnnotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspectjAnnotation {
    @Pointcut("execution(* com.aaa.dao.impl.*.*(..))")
    public void myPointCut(){

    }
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知"+joinPoint.getSignature().getName());
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最终通知"+joinPoint.getSignature().getName());
    }
    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知开启"+proceedingJoinPoint.getSignature().getName());
        Object result=proceedingJoinPoint.proceed();
        System.out.println("环绕通知关闭"+proceedingJoinPoint.getSignature().getName());
        return result;
    }
    @AfterReturning(value = "myPointCut()",returning = "result")
    public void myAfterReturning(JoinPoint joinPoint,Object result){
        System.out.println("后置通知"+joinPoint.getSignature().getName());
        System.out.println("result:"+result);
    }
    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void myThrow(JoinPoint joinPoint,Throwable e){
        System.out.println("异常通知:"+joinPoint.getSignature().getName()+"message"+e.getMessage());
    }
}

注解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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

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

测试

package com.aaa.aspectjAnnotation;

import com.aaa.dao.InsuranceService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyAspectjAnnotationTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("aspectjAnnotation/aspectjAnnotation.xml");
        InsuranceService insuranceService=applicationContext.getBean(InsuranceService.class);
        String string=insuranceService.buyInsurance();
        System.out.println(string);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值