开始学习Spring全家桶
文章目录
- 1. IoC
- 定义
- 为什么叫控制反转?
- 实现
- IoC 容器创建 bean 的两种⽅式
- IoC DI
- 特殊字符的处理
- Spring 中的bean创建类型 -- scope
- Spring 的继承 -- parent
- Spring 的依赖 -- depends-on
- Spring 读取外部资源 -- context:property-placeholder
- Spring p 命名空间
- Spring工厂方法
- SpringIoC自动装载autowire
- Spring IoC 基于注解的开发
- 实际开发的使⽤
- Spring IoC 底层实现
- Spring AOP
- AOP底层
- AOP实际注解开发
1. IoC
定义
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理
为什么叫控制反转?
- 控制 :指的是对象创建(实例化、管理)的权力
- 反转 :控制权交给外部环境(Spring 框架、IoC 容器)
在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
实现
1. 创建maven工程,在pom.xml中加Spring依赖(为了方便可以加上Lombok)
<dependencies>
<!--Spring框架依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!--Lombok依赖(可有可无)-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
注:加入Lombok后,可以直接在类上用@Data/@Getter/@Setter.....等注解隐式封装类,如有个Student类用了Lombok的@Data:
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
}
效果:隐式封装,减少代码量
注意:第一次使用Lombok需要在Settings的Plugins里面安装插件
2. 在 resources 路径下创建 spring.xml,并添加Bean
- 简单来说,Bean 代指的就是那些被 IoC 容器所管理的对象
- 我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--自定义的bean信息,class指定的是 java文件夹路径下的 类的路径-->
<bean id="student" class="Entity.Student"></bean>
</beans>
3.IoC 容器通过读取 spring.xml 配置⽂件,加载 bean 标签来创建对象
4.调⽤ API 获取 IoC 容器中已经创建的对象
public class Test01 {
public static void main(String[] args) {
//传统创建对象方法
// Student student = new Student();
//通过IoC创建对象
//创建IoC容器读取spirng.xml配置文件
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring.xml");
//IoC容器会根据参数id,读取相应的bean,返回一个Object 类型的对象
Student student = (Student) applicationContext.getBean("student");
/*也可以直接传输一个class对象,不过如果xml文件中同一个类配置有两个或以上id,那就会报错
*这种方式不用强制类型转换
Student student = applicationContext.getBean(Student.class);
*/
System.out.println(student);
}
}
IoC 容器创建 bean 的两种⽅式
- 无参构造,类中必须包含有无参构造,默认
<!--原理是先调用无参构造,再使用set方法赋初值,而不是有参构造。初值可有可无-->
<bean id="student" class="Entity.Student">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="22"></property>
</bean>
- 有参构造,类中必须包含对应参数的有参构造 -- constructor-arg
方式一:按照index赋值,index代表构造器里面参数顺序,0代表第一个参数
<bean id="student3" class="Entity.Student">
<constructor-arg index="1" value="王五"></constructor-arg>
<constructor-arg index="0" value="3"></constructor-arg>
<constructor-arg index="2" value="18"></constructor-arg>
</bean>
方式二:根据name赋值,name代表对应的属性
<bean id="student3" class="Entity.Student">
<constructor-arg name="name" value="王五"></constructor-arg>
<constructor-arg name="id" value="3"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
IoC DI
依赖注入(Dependency Injection,简称DI):指 Bean 之间的依赖注⼊,设置对象之间的级联关系
场景:有一个Classes班级类,和一个学生类Student,他们之间有级联关系,班级包含很多学生
1. 创建Classes
@Data
public class Classes {
private Integer id;
private String name;
private List<Student> studentList;
}
2. 创建Student
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
//若Classes中已经有关联信息了,则这里不需要创建关联属性了
//private Classes classes;
}
3. 新建resources下的新文件spring-di.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--此处省略复制粘贴的必备部分-->
<!-- Classes -->
<bean id="classes" class="Entity.Classes">
<property name="id" value="1"></property>
<property name="name" value="⼀班"></property>
<!--关联两个student-->
<property name="studentList">
<list>
<ref bean="student1"></ref>
<ref bean="student2"></ref>
</list>
</property>
</bean>
<!-- Student -->
<bean id="student1" class="Entity.Student">
<property name="id" value="100"></property>
<property name="name" value="张三"></property>
<property name="age" value="22"></property>
<!--在关联级联关系的时候,不能用value,只能用ref-->
<!--<property name="classes" ref="classes"></property>-->
</bean>
<bean id="student2" class="Entity.Student">
<property name="id" value="200"></property>
<property name="name" value="李四"></property>
<property name="age" value="20"></property>
<!--如果Classes里面已经有ref,在Student里面就不用加级联信息了,会造成死循环,栈溢出错误-->
<!--<property name="classes" ref="classes"></property>-->
</bean>
</beans>
注:bean 之间的级联需要使⽤ ref 属性完成映射,⽽不能直接使⽤ value ,否则会抛出类型转换异常
4. 测试
public class Test01 {
public static void main(String[] args) {
//创建IoC容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-di.xml");
//IoC容器创建对象
Classes classes = (Classes) applicationContext.getBean("classes");
Student student1 = (Student) applicationContext.getBean("student1");
Student student2 = (Student) applicationContext.getBean("student2");
//输出
System.out.println(classes);
System.out.println(student1);
System.out.println(student2);
}
}
5. 结果
特殊字符的处理
例如 “一班” 要改成 “<一班>”,错误的写法是:
<property name="name" value="⼀班"></property>
报org.xml.sax.SAXParseException 错误!
正确的写法是:
<property name = "name" ><value> <![CDATA[< ⼀班 >]]> </value></property>
Spring 中的bean创建类型 -- scope
- singleton,单例,表示通过 Spring 容器获取的对象是唯⼀的,默认值
- prototype,原型,表示通过 Spring 容器获取的对象是不同的
- request,请求,表示在⼀次 HTTP 请求内有效
- session,会话,表示在⼀个⽤户会话内有效
注:requset,session 适⽤于 Web 项⽬
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student stu1 = applicationContext.getBean(Student.class);
Student stu2 = applicationContext.getBean(Student.class);
//true
System.out.println(stu1 == stu2);
<bean id = "student" class = "Entity.Student " scope = "prototype" ></property>
Spring 的继承 -- parent
- Spring 继承不同于 Java 中的继承,区别:Java 中的继承是针对于类的,Spring 的继承是针对于对象
- Spring 的继承中,⼦ bean 可以继承⽗ bean 中的所有成员变量的值,不需要类间继承,只要成员变量一致即可
1. 新建一个User类:比Student多了一个sex属性(只能相同或者多)
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private Integer sex;
}
2. 配置Sping.xml文件,对User的Bean标签加上 parent
<bean id="student" class="Entity.Student">
<property name="age" value = "12"></property>
<property name="id" value = "01"></property>
<property name="name" value = "张三"></property>
</bean>
<!--user 继承 student-->
<bean id="user" class="Entity.User" parent="student">
<property name="name" value = "李四"></property>
<property name="sex" value="0"></property>
</bean>
3. IoC容器创建这两个对象,并且打印信息,得到结果
Spring 的依赖 -- depends-on
- ⽤来设置两个 bean 的创建顺序
- IoC 容器默认情况下是通过 spring.xml 中 bean 的配置顺序来决定创建顺序的,配置在前⾯的 bean 会 先创建
- 在不更改 spring.xml 配置顺序的前提下,通过设置 bean 之间的依赖关系来调整 bean 的创建顺序
<bean id="student" class="Entity.Student" depends-on="user"></bean> <bean id="user" class="Entity.User"></bean>
Spring 读取外部资源 -- context:property-placeholder
场景:实际开发中,数据库的配置⼀般会单独保存到后缀为 properties 的⽂件中,⽅便维护和修改,如果使⽤ Spring 来加载数据源,就需要在 spring.xml 中读取 properties 中的数据,这就是读取外部资源
<beans>头标签需要加上:
xmlns:context="http://www.springframework.org/schema/context"
user = root password = 000000 url = jdbc:mysql://localhost:3306/test driverName = com.mysql.cj.jdbc.Driver
2. 创建DataSource类
@Data
public class DataSource {
private String user;
private String password;
private String url;
private String driverName;
}
3. 配置spring-properties.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- 此处省略复制粘贴部分-- >
<!--导入文件-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<!--spring EL表达式 :${变量名}-->
<bean id ="dataSource" class="Entity.DataSource">
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="url" value="${url}"></property>
<property name="driverName" value="${driverName}"></property>
</bean>
</beans>
4. IoC创建对象及其输出结果:
Spring p 命名空间
p可以简化bean对象属性的赋值,包括级联关系的映射
使用p命名需要在<beans>头标签加上:
xmlns:p="http://www.springframework.org/schema/p"
以Student和 Class举例,配置spring-p.xml:
<bean id = "student" class = "Entity.Student" p:id = "1" p:name = " 张三 "p:age = "22" p:classes-ref = "classes" > </bean><bean id = "classes" class = "Entity.Classes" p:id = "1" p:name = " ⼀班 " > </bean>
Spring工厂方法
- 静态工厂方法
1. 创建Car类
@Data
@AllArgsConstructor
public class Car {
private Integer num;
private String brand;
}
2. 创建StaticCarFactory类
public class StaticCarFactory {
//value一定为Car , key可以根据序号或者品牌名字都行
private static Map<Integer,Car> carMap;
//静态块,类加载的时候就运行
static {
carMap = new HashMap<Integer, Car>();
carMap.put(1, new Car(1,"奥迪"));
carMap.put(2, new Car(2,"奥拓"));
}
//静态方法
public static Car getCar(Integer num){
return carMap.get(num);
}
}
3.配置spring-factory.xml
<!-- 此为1号汽车的bean对象-->
<bean id ="car1" class="Entity.StaticCarFactory" factory-method="getCar">
<constructor-arg value="1"/>
</bean>
factory-method要指定一个静态方法,constructor-arg 指定一个参数
- 实例工厂方法
1. 创建InstanceFactory类
@Data
@AllArgsConstructor
public class InstanceFactory {
private Map<Integer,Car> carMap;
public InstanceFactory(){
carMap = new HashMap<Integer, Car>();
carMap.put(1,new Car(1,"奥迪"));
carMap.put(2,new Car(2,"奥拓"));
}
public Car getCar(Integer num){
return carMap.get(num);
}
}
2.配置spring-factory.xml
<!--需要实例化工厂-->
<bean id="instanceFactory" class="Entity.InstanceFactory"></bean>
<!-- 通过工厂方法创建对象-->
<bean id="car2" factory-bean="instanceFactory" factory-method="getCar">
<constructor-arg type="java.lang.Integer" value="2"/>
</bean>
3.测试
Car car2 = (Car) applicationContext.getBean("car2");
静态工厂和实例工厂区别
- 静态工厂不需要实例化工厂对象,spring.xml 中 是class + factory-method 的形式
- 实例工厂需要实例化工厂对象,spring.xml是factory-bean + factory-method 的形式
SpringIoC自动装载autowire
不需要配置property,更加简便方式完成DI,IoC容器自动选择bean注入
自动装载两种方式:
- byName,通过属性名完成自动装载
- byType,通过属性对应的数据类型完成自动装载
byName:属性名 和 bean id 要一致
1. 创建Person类 (注意:Car 类型的属性名为car1)
@Data
public class Person {
private Integer Id;
private String name;
//这里属性名为car1
private Car car1;
}
2. 创建Spirng-autowire,配置Car 和 Person的 bean,自动DI
<!-- bean标签的id也要为car1-->
<bean id ="car1" class="Entity.Car" >
<property value="1" name="num"/>
<property value="奥迪" name="brand"/>
</bean>
<!-- 配置autowire为byName-->
<bean id="person" class="Entity.Person" autowire="byName">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
byType:要求Car bean只有一个,才能自动装载
<bean id="person" class="Entity.Person" autowire="byType">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
<bean id="car2" class="Entity.Car">
<constructor-arg name="num" value="1"></constructor-arg>
<constructor-arg name="brand" value="奥迪"></constructor-arg>
</bean>
Spring IoC 基于注解的开发
Spring IoC 的作⽤是帮助开发者创建项⽬中所需要的 bean,同时完成 bean 之间的依赖注⼊关系
实现该功能有两种⽅式:
- 基于 XML 配置
- 基于注解
基于注解有两步操作,缺⼀不可:
1、xml配置⾃动扫包
<context:component-scan base-package="Entity"> </context:component-scan>
2、在对应的类添加@Component注解
@Data
@Component(value = "student") //这个value就是bean id ,默认的也是首字母小写
public class Student {
private Integer age;
private String name;
}
以上步骤相当于在xml中配置如下,(使用的时候直接getBean就行)
<bean id="student" class="Entity.Student"> </bean>
DI 注解
1.给DateSource成员赋值 用@Value
@Data
@Component(value = "ds")
public class DataSource {
@Value("root")
private String user;
@Value("root")
private String password;
@Value("jdbc:mysql://localhost:3308/library")
private String url;
@Value("com.mysql.cj.Driver")
private String driverName;
}
2.给Repostory中的DataSource类型的成员加上@Autowired
@Data
@Component(value = "myrepo")
public class Repository {
@Autowired //表示有级联关系
private DataSource dataSource;
}
注:@Autowired 默认是通过 byType 进⾏注⼊的,如果要改为 byName,需要配置 @Qualifier 注解来完成
@Autowired
@Qualifier(value = "ds")
private DataSource dataSource;
以上就完成了DI的注解操作!
实际开发的使⽤
实际开发中我们会将程序分为三层:
- Controller
- Service
- Repository(DAO)
关系: Controller 调用Service;Service 调用Repository;Repository访问数据库
- 实际开发中可以根据业务需求分别使用@Controller、@Service、@Repository 注解来代替@Component标注控制层类、业务层类、持久层类
举一个层层调用的例子:
- Controller
@Setter
@Controller //代替@Component
public class MyController {
@Autowired //自动DI
private MyService myService;
//模拟客户端请求 -> 调用sevice层接口
public String service(Double score){
return myService.doService(score);
}
}
- Service
------------------------函数式接口-------------------------
//不能加@Component,因为不能实例化接口
public interface MyService {
public String doService(Double score);
}
---------------------实现类------------------------------
@Setter
@Service
public class MyServiceImpl implements MyService{
@Autowired //自动DI
private MyRepository myRepository;
public String doService(Double score) {
return myRepository.doRepository(score);
}
}
- Repository
--------------------------接口------------------------
//不能加@Component,因为不能实例化接口
public interface MyRepository {
public String doRepository(Double score);
}
-------------------------实现类-----------------------
@Repository
public class MyRepositoryImpl implements MyRepository{
@Override
public String doRepository(Double score) {
String res = "";
if(score < 60) res="不及格";
else res ="及格";
return res;
}
}
- spring.xml
<context:component-scan base-package="controller"></context:component-scan>
<context:component-scan base-package="service"></context:component-scan>
<context:component-scan base-package="repository"></context:component-scan>
- Test
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
MyController myController = applicationContext.getBean(MyController.class);
System.out.println(myController.service((double) 80));
Spring IoC 底层实现
- 根据需求编写 XML ⽂件,配置需要创建的 bean
<!--student类-->
<bean id="student" class="Entity.Student" >
<property name="id" value="01"></property>
<property name="age" value="18"></property>
<property name="name" value="张三"></property>
</bean>
- 编写程序读取 XML ⽂件,获取 bean 相关信息,类、属性、id
注意:读取xml需要在pom.xml中加入dom4j依赖
<!--dom4j-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
- 根据第 2 步获取到的信息,结合反射机制动态创建对象,同时完成属性的赋值
- 将创建好的 bean 存⼊ Map 集合,设置 key - value 映射,key 就是 bean 中 id 值,value 就是 bean 对象
- 提供⽅法从 Map 中通过 id 获取到对应的 value
自定义一个类实现ApplicationContext接口
/**
* @Author 苦恼的java小宝
* @Date 2022/5/10 16:28
* @ClassName: ioc.MyClassPathXmlApplicationContext
* @Version 1.0
*/
public class MyClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> iocMap;
//有参构造
public MyClassPathXmlApplicationContext(String path) {
iocMap = new HashMap<>();
//解释XML
parseXml(path);
}
public void parseXml(String path) {
SAXReader saxReader = new SAXReader();
try {
//import org.dom4j.io.SAXReader;
Document document = saxReader.read(path);
//拿到beans大标签
Element root = document.getRootElement();
//子标签迭代器->拿到每个bean
Iterator<Element> roorIter = root.elementIterator();
//寻找每个bean的子标签->拿到每个property
while(roorIter.hasNext()){
Element bean = roorIter.next();
String id = bean.attributeValue("id");
String className = bean.attributeValue("class");
//通过反射创建对象
Class clazz = Class.forName(className);
Constructor constructor = clazz.getConstructor();//无参
Object obj = constructor.newInstance();
//给对象属性赋值(通过获取setter方法)
Iterator<Element> beanIter = bean.elementIterator();
//寻找每个属性
while(beanIter.hasNext()){
Element property = beanIter.next();
//获取到<property>标签里面的name值 与 value值 ,取出来为String类型
String propertyName = property.attributeValue("name");
String propertyValue = property.attributeValue("value");
//获取setter方法的名字 方法名:setName() setId()
String methodName = "set" + propertyName.substring(0,1).toUpperCase() +propertyName.substring(1);
//获取属性
Field field = clazz.getDeclaredField(propertyName);
System.out.println(field.getType());
//获取方法(通过 方法名和参数列表 才能确定唯一方法)
Method method = clazz.getMethod(methodName, field.getType());
Object value = propertyValue;
//类型转换
switch (field.getType().getName()){
case "java.lang.Integer":
value = Integer.parseInt(propertyValue);
break;
case "java.lang.Double":
value = Double.parseDouble(propertyValue);
break;
}
//调用setter方法
method.invoke(obj,value);
}
//存入map
iocMap.put(id,obj);
}
} catch (DocumentException | ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String s) throws BeansException {
return iocMap.get(s);
}
}
Spring AOP
EX:若要在每个方法 的前后 打印日志,那么传统方法如下图:
显而易见,上述形式的代码维护性差,没有代码复⽤性,使⽤ AOP 进⾏优化,如下图所示:
上述图片用一个切片对象进行代理,所有方法都可以通过代理对象来运行,日志需要改变的时候,只需要改变一个切面对象的代码即可,不需要逐个方法体的代码都改。 实现非业务代码和业务代码的分离
AOP底层
新建一个AOP pakage
public interface Cal {
public int add(int num1,int num2);
public int sub(int num1,int num2);
public int mul(int num1,int num2);
public int div(int num1,int num2);
}
public class CalImpl implements Cal {
@Override
public int add(int num1, int num2) {
int result = num1 + num2;
return result;
}
@Override
public int sub(int num1, int num2) {
int result = num1 - num2;
return result;
}
@Override
public int mul(int num1, int num2) {
int result = num1 * num2;
return result;
}
@Override
public int div(int num1, int num2) {
int result = num1 / num2;
return result;
}
}
- 使⽤动态代理的⽅式来实现
- 创建 MyInvocationHandler 类,实现 InvocationHandler 接⼝,⽣成动态代理类
- 动态代理类,需要动态⽣成,需要获取到委托类的接⼝信息,根据这些接⼝信息动态⽣成⼀个代理类
- 然后再由 ClassLoader 将动态⽣成的代理类加载到 JVM
3、创建 MyInvocationHandler 类,实现 InvocationHandler(调用处理程序) 接⼝
public class MyInvocationHandler implements InvocationHandler {
//委托对象
private Object object = null;
//由委托对象生成代理对象
public Object bind(Object object){
this.object = object;
/*
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
*/
return Proxy.newProxyInstance(
object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实现业务代码和⾮业务代码的解耦合
System.out.println(method.getName()+"⽅法的参数是"+
Arrays.toString(args));
//执行业务代码
Object result = method.invoke(this.object,args);
System.out.println(method.getName()+"⽅法的结果是"+ result);
return result;
}
}
4.测试类
public class Test02 {
public static void main(String[] args) {
//创建委托对象
Cal cal = new CalImpl();
//返回代理对象
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Cal proxy = (Cal) myInvocationHandler.bind(cal);
proxy.add(1,2);
proxy.sub(1,2);
proxy.mul(1,2);
proxy.div(1,2);
}
}
AOP实际注解开发
<!--Spring AOP-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
@Component
@Aspect
public class LoggerAspect {
//表示在AOP包下的CalImpl实体类中的任何返回值为int的方法 之前调用
@Before("execution(public int aop.CalImpl.*(..))")
public void before(JoinPoint joinPoint){
//获得方法名
String name = joinPoint.getSignature().getName();
//获得方法参数
String args = Arrays.toString(joinPoint.getArgs());
System.out.println(name+"方法的参数是"+args);
}
@After("execution(public int aop.CalImpl.*(..))")
public void after(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
System.out.println(name+"⽅法执⾏完毕");
}
@AfterReturning(value = "execution(public int " +
"aop.CalImpl.*(..))",returning = "result")
public void afterReturn(JoinPoint joinPoint,Object result){
String name = joinPoint.getSignature().getName();
System.out.println(name+"⽅法的结果是"+result);
}
@AfterThrowing(value = "execution(public int " +
"aop.CalImpl.*(..))",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String name = joinPoint.getSignature().getName();
System.out.println(name+"⽅法抛出异常"+ex);
}
}
- @Component,将切⾯类加载到 IoC 容器中
- @Aspect,表示该类是⼀个切⾯类
- @Before,表示⽅法的执⾏时机是在业务⽅法之前,execution 表达式表示切入点是委托类的哪个方法
- @After,表示⽅法的执⾏时机是在业务⽅法结束之后
- @AfterReturning,表示⽅法的执⾏时机是在业务⽅法返回结果之后,returning 是将业务⽅法的返回值与切⾯类⽅法的形参进⾏绑定
- @AfterThrowing,表示⽅法的执⾏时机是在业务⽅法抛出异常之后,throwing 是将业务⽅法的异常与切⾯类⽅法的形参进⾏绑定
3.配置Sping-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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!-- ⾃动扫包 -->
<context:component-scan base-package="aop"></context:component-scan>
<!-- 为委托对象⾃动⽣成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
public class Test01 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-aop.xml");
//内部已经自动配置代理对象,以下方法都由代理对象执行
Cal calImpl = (Cal) applicationContext.getBean("calImpl");
calImpl.div(10,3);
calImpl.add(10,3);
calImpl.sub(10,3);
calImpl.mul(10,3);
}}