文章目录
- 1. Spring介绍
- 1.1 Spring的体系结构
- 2.DI/Ioc(依赖注入/控制反转)
- 2.1 依赖及注解说明
- 1. lombok
- 2. spring-context
- 2.2 Bean和Spring 上下文的配置方式
- 方式1:基于`xml文件`的配置
- 方法2: 基于java注解配置bean
- 方法3:自动化配置
- 2.3 Bean的实例化方式
- 方式1:静态工厂
- 方式2:实例工厂
- 3.AOP(面向切面编程)
- 3.1 AOP术语
- 3.2 AOP依赖导入
- 3.3 代理
- JDK动态代理(基于接口代理)
- CGLIB代理(基于类继承代理)
- AOP和代理模式之间的关系
- 3.4 Spring AOP
- 基于注解的AOP案例
1. Spring介绍
概念: Spring 是一个开源的企业级应用程序开发框架,它为 Java 应用程序提供了全面的基础设施支持和丰富的功能模块。Spring 的目标是简化 Java 开发,提高开发效率、代码质量和可维护性。
- Aim: 解决企业级应用开发的复杂性而存在;
- 核心: Spring的核心是提供一个容器。
这个容器会创建和管理应用的组件,组件称为Bean,通过这个容器将bean装配在一起,形成一个完整的应用程序。
容器称为Spring应用上下文;
将bean组装在一起的行为是通过依赖注入DI的模式实现;- 作用:
- 让Java
Bean之间
进行更有效的解耦
;(DI/Ioc)- Spring 支持
面向切面编程
;(AOP)整合其他框架和技术
; (Hibernate、MyBatis、Spring MVC、Spring Data、Spring Security)- 提供了
声明式事务管理
的机制;- 强大的
测试
支持;
Spring相关的开发模式
- SSH(Spring-Struts-Hibernate)
Spring框架:Spring作为一个轻量级的容器,负责管理应用程序中的对象、依赖注入、事务管理等。它提供了许多功能,如IoC(控制反转)、AOP(面向切面编程)等,用于简化开发过程和增加代码的可维护性。
Struts框架:Struts是一个基于MVC(Model-View-Controller)设计模式的Web框架。它负责处理HTTP请求、将请求映射到相应的处理器(Action)进行处理,并将处理结果呈现给用户。Struts框架提供了一套可扩展的Action处理机制,用于处理用户请求和管理页面跳转。
Hibernate框架:Hibernate是一个对象关系映射(ORM)框架,用于将数据库中的数据映射到Java对象中。它负责处理数据持久化的细节,包括数据库连接、SQL生成、事务管理等。Hibernate提供了简单的API和查询语言,使得开发人员可以更方便地操作数据库。
//
- SSM(Spring-SpringMVC-MyBatis)
Spring框架:Spring作为一个轻量级的容器,负责管理应用程序中的对象、依赖注入、事务管理等。它提供了许多功能,如IoC(控制反转)、AOP(面向切面编程)等,用于简化开发过程和增加代码的可维护性。
SpringMVC框架:SpringMVC是一个基于MVC(Model-View-Controller)设计模式的Web框架。它负责处理HTTP请求、将请求映射到相应的处理器(Controller)进行处理,并将处理结果呈现给用户。SpringMVC框架提供了一套灵活的处理器映射机制、数据绑定和视图解析等功能,用于构建Web应用程序的前端控制器。
MyBatis框架:MyBatis是一个持久层框架,用于将数据库操作映射到Java对象中。它通过XML或注解配置,提供了简单的数据访问对象(DAO)的编写方式。MyBatis框架负责数据库连接、SQL执行、结果映射等,使得开发人员可以更方便地操作数据库。
1.1 Spring的体系结构
1.Core Container(核心容器)
Spring的核心容器是其他模块建立的基础。
- Beans模块:提供了
BeanFactory
,是工厂模式的经典实现,Spring将管理对象称为Bean。- Core核心模块:提供了Spring框架的基本组成部分,包括
IoC和DI
功能。- Context上下文模块:建立在Core和Beans模块的基础之上,它是访问定义和配置的任何对象的媒介。其中
ApplicationContext接口
是上下文模块的焦点。- Context-support模块:提供了对
第三方库嵌入Spring应用的集成支持
,比如缓存(EhCache、Guava、JCache)、邮件服务(JavaMail)、任务调度(CommonJ、Quartz)和模板引擎(FreeMarker、JasperReports、速率)。- SpEL模块:是Spring 3.0后新增的模块,它提供了Spring Expression Language支持,是运行时查询和操作对象图的强大的
表达式语言
。
2.Data Access/Integration(数据访问/集成)
- JDBC模块:提供了一个JDBC的抽象层,大幅度地减少了在开发过程中对数据库操作的编码。
- ORM模块:对流行的
对象关系映射API
,包括JPA、JDO和Hibernate提供了集成层支持。- OXM模块:提供了一个
支持对象/ XML映射
的抽象层实现,如JAXB、Castor、XMLBeans、JiBX和XStream。- JMS模块:指
Java消息传递
服务,包含使用和产生信息的特性,自4.1版本后支持与Spring-message模块的集成。- Transactions事务模块:支持对实现
特殊接口
以及所有POJO类的编程和声明式的事务管理。
3.Web
- WebSocket模块:它提供了WebSocket和SockJS的实现,以及对STOMP的支持。
- Servlet模块:也称为Spring-webmvc模块,包含了Spring的(MVC)和REST Web Services实现的Web应用程序。
- Web模块:提供了基本的Web开发集成特性,例如:多文件上传功能、使用Servlet监听器来初始化IoC容器以及Web应用上下文。
- Portlet模块:提供了在Portlet环境中使用MVC实现,类似Servlet模块的功能。
4.其他模块
- AOP模块:提供了
面向切面
编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以降低耦合性。- Aspects模块:提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的面向切面编程(AOP)框架。
- Instrumentation模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
- Messaging模块:Spring 4.0以后新增的模块,它提供了对
消息传递
体系结构和协议的支持。- Test模块:提供了对单元测试和集成测试的支持。
2.DI/Ioc(依赖注入/控制反转)
Spring的作用之一:让Java
Bean之间
进行更有效的解耦
理解Bean 之间的解耦:
传统的 Java 开发中,对象之间的依赖关系通常是通过直接实例化和引用其他对象来建立的,
这导致了高度的耦合性。---------------------------------------------------------------------------
举例:
public class UserService {private UserDao userDao = new UserDao();public void createUser(User user) {// 使用 userDao 对象进行用户数据的持久化操作userDao.save(user);}
}这里存在两个类:UserService 和 UserDao。
UserService 是一个用户服务类,依赖于 UserDao 来进行用户数据的持久化操作。-------------------------------------------------------------------------------------------
UserService 类在自己的代码中直接创建了一个 UserDao 对象,并将其作为成员变量进行引用。
这种方式存在的问题:
1. Service 类与具体的 User 类紧密耦合在一起,User类如果发生改变,service也需要修改。
2. service如果被使用,还需要额外管理UserDao对象的生命周期。
3. 进行测试项目时,无法将service单独进行测试。
概念
IOC(Inversion of Control)和 DI(Dependency Injection)是紧密相关的概念,主要用于
解耦对象之间的依赖关系
,提高代码的灵活性、可维护性和可测试性。
//
IOC(控制反转) 是一种设计原则
,“对象的控制权的转移”
- 指的是将对象的创建和依赖关系的管理交给容器来控制,而不是由应用程序代码显式地创建和管理对象(在传统的编程模型中,应用程序代码负责创建和管理对象,而在IOC模式下,这种控制权被转移到了容器中)。
DI(依赖注入) 是IOC的一种
实现
方式,“描述对象之间的依赖关系是通过注入的方式解决”
- 指通过容器将依赖关系注入到对象中。
在依赖注入中,对象不再负责自己的依赖关系的创建,而是通过构造函数、属性或方法参数等方式接收依赖对象。
依赖注入可以通过接口、注解或配置来实现
,目的是实现对象之间的解耦和灵活性。
2.1 依赖及注解说明
1. lombok
<!-- 简化实体类的开发,通过注解自动化生成Java类的样板代码,如Getter、Setter、构造函数、equals()和hashCode()等方法--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency>
创建一个实体类,使用@Data注解
自动生成get set 等方法
package com.imooc.pojo;import lombok.Data;@Data
public class Student {private long id;private String name;private int age;
}
测试类中直接创建Student对象并赋值。
package com.imooc.test;import com.imooc.pojo.Student;public class UserDemo {public static void main(String[] args) {Student student = new Student();student.setId(1);student.setName("tudou");student.setAge(2);System.out.println(student);}
}
2. spring-context
spring-context模块是Spring框架的核心模块之一,提供了IoC(控制反转)容器的功能,以及其他与应用程序上下文相关的特性。
<!-- Spring上下文依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.11.RELEASE</version></dependency>
2.2 Bean和Spring 上下文的配置方式
方式:
- 基于xml文件;
- 基于java注解的配置;
- 自动化配置
方式1:基于xml文件
的配置
1.在resource下创建一个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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
创建实体类
package com.imooc.pojo;import lombok.Data;@Data
public class Student {private long id;private String name;private int age;
}
在xml中引入实体类
id:对象名
class:对象的模板类(所有交给Ioc管理的类,必须有无参构造方式)
成员变量通过property标签赋值
- name:成员变量名
- value:成员变量值(基本数据类型)
- ref:将ioc中的另一个bean赋值给当前bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="student" class="com.imooc.pojo.Student"><property name="id" value="1"></property><property name="name" value="zhangsan"></property><property name="age" value="56"></property><property name="address" ref="address"></property></bean><bean id="address" class="com.imooc.pojo.Address"><property name="city" value="beijing"></property><property name="home" value="qinghau"></property></bean>
</beans>
测试
public class UserDemo {public static void main(String[] args) {Student student = new Student();student.setId(1);student.setName("tudou");student.setAge(2);System.out.println(student);//加载配置文件ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");Student student1 = (Student)classPathXmlApplicationContext.getBean("student");System.out.println(student1);}
}
方法2: 基于java注解配置bean
注解 | 说明 |
---|---|
@Configuration | 表示当前类是一个配置类,相当于之前的spring.xml文件 |
@Bean | 返回一个由Spring管理的bean对象。 |
package com.imooc.config;import com.imooc.pojo.Address;
import com.imooc.pojo.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class StudentConfig {@Beanpublic Student student(){Student student = new Student();student.setId(2);student.setName("lisi");student.setAge(66);student.setAddress(address());return student;}@Beanpublic Address address(){Address address = new Address();address.setCity("南京");address.setHome("家");return address;}
}
import com.imooc.config.StudentConfig;
import com.imooc.pojo.Address;
import com.imooc.pojo.Student;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class StudentDemo {public static void main(String[] args) {// 创建基于注解的应用程序上下文AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(StudentConfig.class);// 获取配置的beanStudent bean = acac.getBean(Student.class);
// Address bean1 = acac.getBean(Address.class);// 使用beanSystem.out.println(bean);}
}
方法3:自动化配置
@Component 注解通常与其他相关的注解(如 @Service、@Repository、@Controller 等)一起使用,用于
标记不同层次或类型的组件
,以告诉 Spring 框架要扫描哪些包来寻找被注解的组件。这样,Spring 容器会自动实例化
和管理
这些组件,以供应用程序使用。
注解 | 说明 |
---|---|
@Component | 将一个类标记为 Spring 托管的组件 ,Spring 容器会自动扫描并实例化 这些组件,并将它们纳入到应用程序上下文中 |
@Service | 标记服务层组件 ,表示该组件用于处理业务逻辑。通常,服务层组件被用于封装业务逻辑,处理数据的获取、转换、计算和操作等任务。 |
@Repository | 标记持久层组件 ,表示该组件用于封装数据访问逻辑。通常,持久层组件用于与数据库或其他数据存储进行交互,执行数据的读取、写入、更新和删除等操作。 |
@Controller | 用于标记控制层组件 ,表示该组件用于处理请求和响应。通常,控制层组件接收用户请求,调用适当的服务层组件处理请求,并返回响应给用户。 |
//创建配置类
import com.imooc.pojo.Student;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;@Component("student4")
@Service
public class StudentService {public Student createStudentt(){Student student = new Student();student.setName("画虎");return student;}
}
xml自动化配置
在spring.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 http://www.springframework.org/schema/context/spring-context.xsd"><!--注解组件扫描,扫描指定的基本包及其子包下的类,识别使用@Component注解--><context:component-scan base-package="com.imooc"></context:component-scan></beans>
测试
public class StudentDemo4 {public static void main(String[] args) {ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");StudentService studentService= classPathXmlApplicationContext.getBean(StudentService.class);Student studentt = studentService.createStudentt();System.out.println(studentt);}
}
java注解自动化扫描
package com.imooc.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;//@Configuration声明加载配置类,@ComponentScan指定要扫描的包和子包
@Configuration
@ComponentScan(basePackages = "com.imooc")
public class StudentAutoConfig {}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class StudentDemo5 {public static void main(String[] args) {// 创建一个注解配置的应用上下文AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(StudentAutoConfig.class);// 从应用上下文中获取 StudentService 的实例StudentService bean = annotationConfigApplicationContext.getBean(StudentService.class);// 调用 StudentService 的 createStudentt() 方法创建一个学生对象Student studentt = bean.createStudentt();// 打印学生对象System.out.println(studentt);}
}
2.3 Bean的实例化方式
方式1:静态工厂
要求用户创建一个静态工厂的方法来创建bean的实例,其bean配置中的class属性所指的不再是bean的实现类,而是静态工厂类。
- 使用factory-method属性指定创建的静态工厂方法
方式2:实例工厂
在工厂类中,直接创建Bean实例;
在配置文件中,先创建配置工厂
再创建实例工厂指向该配置工厂,再指定方法
<!-- 配置工厂--><bean id="studentFactory" class="com.imooc.factory.StudentFactory"/>
<!-- 实例工厂--><bean id="student3" factory-bean="studentFactory" factory-method="createStudents"></bean>
3.AOP(面向切面编程)
AOP(面向切面编程)是一种软件开发的编程范式,它的目的是通过将横切逻辑与核心业务逻辑分离,以提高代码的模块性、可维护性和可重用性。
作用:
- 简化代码:把方法中固定位置的重复代码抽取出来,让被抽取的方法更专注于实现自己的核心业务;
Reason:
在传统的业务处理代码中,通常都会进行事务处理
、日志记录
等操作。
- 使用
OOP(面向对象)
以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中
。- 如果想要
关闭某个功能
,或者对其进行修改,就必须要修改所有的相关方法
。这不但增加了开发人员的工作量,而且提高了代码的出错。/
AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。
3.1 AOP术语
一文弄懂AOP概念
关键字 | 解释 | 方法 |
---|---|---|
Aspect | 切面 | 用于封装横切关注点 的类(也称封装通知方法的类)//封装完之后,一个横切关注点表示一个通知方法。 |
Joinpoint | 连接点 | 逻辑概念,抽取横切关注点的位置 |
Pointcut | 切入点 | 定位连接点 的方式 |
Advice | 通知 | 切面 在特定连接点 执行的代码 |
Weaving | 织入 | 将切面 应用到目标对象 中的过程 |
Proxy | 代理 | 将通知 应用到目标对象 ,被动态创建的对象 。 |
3.2 AOP依赖导入
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.0.11.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.11.RELEASE</version></dependency>
3.3 代理
在AOP(面向切面编程)中,代理是实现切面功能的关键机制。
- 代理对象是在目标对象周围创建的,它将目标对象包装起来,并拦截对目标对象的方法调用。通过代理,AOP能够实现横切关注点的分离,将与核心业务逻辑无关的横切关注点(如日志记录、事务管理、安全性检查等)从目标对象中抽离出来。
代理对象和目标对象的关系
举例:每个员工去老板办公室和老板交谈,老板首先要确认是不是内部员工,代理的作用相当于是一个工卡,来帮助老板快速识别内部员工。
//具体:每个员工要去老板办公室和老板交谈时,首先需要通过工卡验证身份。工卡(代理对象)会拦截员工的访问请求,并对员工的身份进行验证。只有通过验证的员工(合法的方法调用)才能继续与老板(目标对象)进行交谈。工卡(代理对象)在验证身份的同时,还可以执行其他额外的任务,例如日志功能:记录员工的访问时间、统计员工的访问次数等。
Spring AOP 的两种代理模式
JDK动态代理:
- JDK动态代理是
基于接口
的代理模式。
当目标对象实现了至少一个接口
时,Spring会使用JDK动态代理来创建代理对象。JDK动态代理利用Java的反射机制,在运行时动态地创建代理对象。代理对象实现了目标对象相同的接口,并在方法调用前后插入横切逻辑。JDK动态代理要求目标对象实现接口,因此它更适用于基于接口的代理场景。CGLIB代理:
- CGLIB代理是
基于类继承
的代理模式。
当目标对象没有实现任何接口时,或者你希望绕过接口的限制时,Spring会使用CGLIB代理来创建代理对象。CGLIB它通过创建目标对象的子类来实现代理
。代理对象继承了目标对象的类,并重写了目标对象的方法,在方法调用前后添加横切逻辑。CGLIB代理不要求目标对象实现接口,因此更加灵活,适用于更广泛的代理场景。
//注意:使用JDK动态代理类的对象必须实现一个或多个接口。
JDK动态代理(基于接口代理)
实现步骤:
- 定义
目标接口
(其中包含要被代理的方法),定义目标接口的实现类;- 创建一个
代理类
(实现InvocationHandler接口),该类负责拦截方法调用并添加额外的逻辑;- 创建
代理对象
(使用Proxy类中的newProxyInstance方法);- 通过代理对象调用目标接口的方法;
//1. 定义目标接口
public interface Employee {void talkToBoss();
}
------------------------------------------------------------
//2.定义目标接口的实现类
public class EmployeeImpl implements Employee{public void talkToBoss() {System.out.println("我说员工,和老板说话了");}
}//目标接口的另一个实现类
public class EmployeeImpl2 implements Employee{public void talkToBoss() {System.out.println("找老板发工资");}
}----------------------------------------------------------------import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//2.定义代理类
public class EmployeeProxy implements InvocationHandler {//声明目标接口public Employee employee;//创建代理方法public Object createProxy(Employee employee){this.employee=employee;//2.1 类加载器ClassLoader classLoader = EmployeeProxy.class.getClassLoader();//2.2 被代理对象实现所有接口Class[] classes = employee.getClass().getInterfaces();//2.3 使用代理类,进行增强,返回的是代理后的对象return Proxy.newProxyInstance(classLoader,classes,this);}//所有的动态代理方法调用,都会交由invoke()方法处理//proxy:被代理后的方法//method:要被执行的方法信息(反射)//args:执行方法需要的参数public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//在方法前添加额外逻辑System.out.println("确认身份");//调用目标方法Object invoke = method.invoke(employee, args);//在方法后添加逻辑System.out.println("交谈完毕");return invoke;}
}
---------------------------------------------------------
//3.测试
public class Test {public static void main(String[] args) {//3.1 创建代理对象EmployeeProxy employeeProxy = new EmployeeProxy();//3.2 创建目标对象 //员工1找老板EmployeeImpl employee = new EmployeeImpl();//3.3执行方法Employee proxy = (Employee) employeeProxy.createProxy(employee);proxy.talkToBoss();//员工2找老板EmployeeImpl2 employee2 = new EmployeeImpl2();Employee proxy1 = (Employee) employeeProxy.createProxy(employee2);proxy1.talkToBoss();}
}
CGLIB代理(基于类继承代理)
步骤
- 添加依赖;
- 创建目标类(将被代理)
- 编写拦截器类
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;// 定义目标类
class Employee {public void talkToBoss() {System.out.println("与老板交谈");}
}// 实现MethodInterceptor接口的代理处理器类
class EmployeeInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 在目标方法执行前添加额外逻辑System.out.println("确认员工身份");// 调用目标方法Object result = proxy.invokeSuper(obj, args);// 在目标方法执行后添加额外逻辑System.out.println("交谈完毕");return result;}
}public class Main {public static void main(String[] args) {// 创建Enhancer对象Enhancer enhancer = new Enhancer();// 设置目标类enhancer.setSuperclass(Employee.class);// 设置代理处理器enhancer.setCallback(new EmployeeInterceptor());// 创建代理对象Employee proxy = (Employee) enhancer.create();// 通过代理对象调用目标方法proxy.talkToBoss();}
}
AOP和代理模式之间的关系
代理模式
- 是一种
结构设计模式
,通过创建一个代理对象来控制原始对象的访问,旨在不改变原始对象的情况下,对其进行增强和控制访问。AOP
- 一种
编程范式
,旨在通过横切关注点(日志、事务等)从核心业务逻辑中分离出来,实现代码的模块化和重用。代理模式
可以用作实现AOP
的一种技术手段
3.4 Spring AOP
AspectJ:基于java的AOP框架;
- 基于xml
- 基于注解
基于注解的AspectJ
注解 | 作用 |
---|---|
@Aspect: | 将一个类标记为切面类 。 |
@Pointcut: | 定义切点 ,指定在哪些连接点上应用切面。 |
@Before: | 定义前置通知 ,在目标方法执行之前执行。 |
@After: | 定义后置通知 ,在目标方法执行之后(包括异常情况)执行。 |
@AfterReturning: | 定义返回通知 ,在目标方法正常返回后执行。 |
@AfterThrowing: | 定义异常通知 ,在目标方法抛出异常时执行。 |
@Around: | 定义环绕通知 ,在目标方法执行前后执行,并可以控制目标方法的执行过程。 |
@EnableAspectJAutoProxy: | 启用AspectJ自动代理 ,用于自动创建代理对象并将切面织入目标对象。 |
通知:每一个横切关注点,在切面上的实现通过通知方法实现。
通知类型 | 说明 |
---|---|
前置通知 | 在目标方法前执行 |
后置通知 | 在目标方法最终结束 后执行(包括正常返回和异常返回) |
返回通知 | 目标方法成功结束 之后 |
异常通知 | 目标方法异常结束之后 |
环绕通知 | 使用try–catch–finally结构环绕整个目标方法,包括上边四种的位置 |
AOP
注意事项
- 切面类和目标类都需要交给IOC容器管理;
- 切面类通过@Aspect注解表示为一个切面
- 在spring配置文件中设置<aop:aspectj-autoproxy开启基于注解的AOP
基于注解的AOP案例
<!--注解组件扫描,扫描指定的基本包及其子包下的类,识别使用@Component注解--><context:component-scan base-package="com.imooc"></context:component-scan>
<!-- 开启基于注解的AOP--><aop:aspectj-autoproxy/>
package com.imooc.aop.BETalkPoxy;//1. 定义目标接口
public interface Employee {void talkToBoss();
}------------------------------------------------
package com.imooc.aop.BETalkPoxy;import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;//2.定义目标接口的实现类
@Component
public class EmployeeImpl implements Employee{public void talkToBoss() {System.out.println("我说员工,和老板说话了");}
}--------------------------------------------------------
package com.imooc.aop.aspect;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//3.定义切面
//日志切面 @component组件类 @Aspect 切面类标识
@Component
@Aspect
public class LoggingAspect {//定位到目标对象某一个方法中 public void方法的返回类型@Before("execution(public void com.imooc.aop.BETalkPoxy.EmployeeImpl.talkToBoss())")public void beforeAdviceMethod(){System.out.println("LoggingAspect 前置通知 记录日志开启");}
}---------------------------------------------
//4.测试package com.imooc.test;import com.imooc.aop.BETalkPoxy.Employee;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class EmployeeAopTest {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");Employee bean = (Employee) context.getBean(Employee.class);bean.talkToBoss();}}