欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AOP

程序员文章站 2022-07-12 14:19:01
...

一、介绍

为什么有AOP
在面向对象编程的系统中,会使用对象来封装一些对象。并通过对象的协作进行完成系统的功能。如员工管理、部门管理、请假管理等功能。现在需要对系统中的所有的新增,修改,删除,等记录下操作的记录,这样需要这样写代码:
AOP
而这些操作都是通过“复制黏贴式”的开发。面向对象在处理这样的业务时由于其封装性导致代码并无法被公用。需要有一种技术来实现方法的扩展(功能增强)。AOP就正是这样的一种技术,它能够配合OOP进行这些通用功能的分离和织入,对业务代码不会造成污染。
AOP的基本概念
什么是AOP?
AOP Aspect-Oriented Programming 面向切面编程。它是一种编程思想能使软件简单,容易维护,更加容易被复用的一种编程方式;AOP只是OOP编程方式的一种补充,并非什么新的技术。
AOP编程方式解决问题的关键在于对关注点的抽象。对系统中的一些分散在多个不相关业务模块中的共同问题(关注点),将这些关注点从各个业务模块中抽象出来是AOP编程的精髓。如日志记录功能,事务管理功能,方法的性能分析等功能从系统业务模块的分离。
对于OOP和AOP的的主要开发流程做一个对比:A B C
OOP 编程基本流程
1)归纳分析系统,抽象领域模型;
2)使用class 来封装领域模型,实现类的功能;
3)把各个类相互协作,组装形成一个完整的功能。


AOP 编程基本流程
1)归纳分析系统中的关注点;
2)分离方面对象,使用OOP 将这些方面封装成一个公用的类;
3)织入到业务功能,按配置织入规则将切面对象(织入或集成)到系统功能中,形成一个增强后的功能。
AOP中的一些关键的专业术语
1)关注点:就是系统中要解决的问题。比如在电子商务系统中,安全验证、日志记录等都属于关注点(Core Concerns);

2)切面(Aspect):用来组织多个Advice,负责管理切入点和增强的关系;

3)增强(Advice):定义何时在切入点执行“织入关注点”;如,在执行方法前执行before,在执行方法后执行after等等。

4)连接点(Joinpoint):明确的某一个被织入代码的点,如方法调用,异常抛出,方法返回等等时间点;

5)切入点(cutpoint):可以织入增强方法的连接点。当连接点满足被增强的要求时,会在该连接点添加增强,此时的连接点就成为切入点。

6)织入(weaving) :织入是指把解决横切问题的切面模板,与系统中的其它核心模块通过一定策略或规则组合到一起的过程;具体的技术方案有:a.动态代理;b.类加载器织入c.编译器织入:AspectJ主要就是是使用这种织入方式

AOP

Spring对AOP的支持

Spring中AOP默认是使用动态代理的方式创建AOP代理的。Spring的AOP代理是由IOC容器负责创建和管理,这样的好处是可以使用容器中的任何一个bean作为“方面”目标。Spring的AOP的设计目标是将AOP的实现和IOC容器进行整合,帮助解决在企业开发中遇到的此类问题。Spring中的AOP也支持AspectJ(面向方面的真正始祖级框架)。

在Spring的AOP开发中,程序员需要做以下三件事情:
1)定义普通的业务类
2)定义切入点,对多个关注点进行横切
3)定义增强,在普通的业务功能中织入关注点的处理


Spring依然提供两种对AOP的配置:
1)XML的方式
2)使用注解进行标注的方式

场景:

Employee balance

现在系统中已经有了很多的业务功能,比如其中的一个EmployeeService类,里面就有方法;addEmployeeBalance()、//添加初始化的薪资 updateEmployeeBalance ()、每次加100,findEmployeeBalance ()。查询工资。
如果在系统完成差不多的时候,这个时候需要对系统中的所有的更新操作(新增,修改,删除)进行记录操作日志,因为数据比较重要,每一部都记录下来,数据变了到底是谁干的一查就清楚了。

当这个需求下来的时候估计很头疼,要在系统中上百个类中去查找到更新的操作,并更改其方法——插入日志记录操作方法。并且要进行测试等等。你是不是顿时觉得天要塌下来了。

AOP就专门治疗这些疑难杂症,你只需要专心编写记录日志的方法,然后使用Spring进行配置能在原有的业务上添加这些增强操作。


二、实例:

1、创建一个maven工程;

2、在pox.xml中引入相关jar包依赖:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.iflytek</groupId>
	<artifactId>myaop</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.3.13.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.13.RELEASE</version>
			<scope>runtime</scope>
		</dependency>
		
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.3.13.RELEASE</version>
		</dependency>
		
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.10</version>
		</dependency>

		<dependency>
			<groupId>aopalliance</groupId>
			<artifactId>aopalliance</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.10</version>
		</dependency>



		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
	</dependencies>
</project>
3、在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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

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

4、代码:

(1、)实体类:

package com.iflytek.domain;

public class Employee {

}
(2、)service:

package com.iflytek.service;

import org.springframework.stereotype.Service;

import com.iflytek.domain.Employee;

@Service
public class EmployeeService {
	
   public int addEmployee(Employee emp) {
      System.out.println("添加员工成功");
      return 0;
   }
   public int delEmployee(Employee emp) {
      System.out.println("删除员工成功");
      return 0;
   }
   public int updateEmployee(Employee emp) {
      System.out.println("修改员工成功");
      return 0;
   }
   public Employee findEmployee(String empno) {
      System.out.println("查询员工成功");
      return new Employee();
   }
}


package com.iflytek.service;

import org.springframework.stereotype.Service;

@Service("optLogger")
public class OptLogger {
   public void writeOpt(String msg){
      System.out.println("日志记录成功");
   }
}


package com.iflytek.service;

import org.springframework.stereotype.Service;

@Service
public class PersonService{
	
	public void save(String name) {
        System.out.println("我是save()方法");
    }

    public void update(String name, Integer id) {
        System.out.println("我是update()方法");
    }

    public String getPersonName(Integer id) {
        System.out.println("我是getPersonName()方法");
        return "xxx";
    }

}


(3、)aop:

package com.iflytek.service;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyInterceptor {
    @Pointcut("execution (* com.iflytek.service.PersonService.add*(..))")
    private void anyMethod() {} // 声明一个切入点,anyMethod为切入点名称
    
    @Pointcut("execution (* com.iflytek.service.EmployeeService.update*(..))")
    private void anotherMethod() {}
    
    // 声明该方法是一个前置通知:在目标方法开始之前执行 
    @Before("anyMethod()")
    public void doAccessCheck() {
        System.out.println("前置通知");
    }
    
    @After(value = "anyMethod()")
    public void closeResource() {
    	System.out.println("关闭数据库连接");
    }
    
    @Before("anotherMethod()")
    public void openSession() {
    	System.out.println("开启session");
    }
}


(4、)测试:

package com.iflytek.test;

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

import com.iflytek.domain.Employee;
import com.iflytek.service.EmployeeService;
import com.iflytek.service.PersonService;

public class SpringAOPTest {
	@Test
	public void interceptorTest() {
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		EmployeeService employeeService = (EmployeeService) cxt.getBean("employeeService");
//		personService.save("xxx");
//		personService.update("zhangsan", 1);
//		personService.getPersonName(1);
		
		employeeService.updateEmployee(new Employee());
	}
}
输出:

AOP