B站视频教学
一·Spring框架概述
1. 概念
2. 特点
- 方便解耦,简化开发(借助Spring提供的IOC容器,将对象之间的依赖关系交给Spring管理)
- AOP编程的支持,在不改变源代码的前提下增加新的功能
- 便于程序测试
- 便于集成其他框架
- 降低JAVAEE API的使用难度
- 便于进行事务的操作
3. 资源信息
spring官网
spring framework下载地址
spring框架如下:
4. 实践: Idea中创建Spring Project(使用Maven管理)
建议先查看后续章节的基础内容再返回实践该project
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
在/src/main/resources中创建bean.xml配置文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="person" class="com.alibaba.springExercise.Person">
<!-- <property name="name" value="spring"></property>-->
</bean>
</beans>
- 在com.alibaba.springExercise下创建一个Person class
package com.alibaba.springExercise;
public class Person {
public Integer age;
public String sex;
public void Person(){}
public void Person(Integer _age, String _sex){
this.age = _age;
this.sex = _sex;
}
public void getProperties(){
System.out.println("Class Person has age & sex properties.");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
public static void main(String[] args) {
//1.加载spring配置文件即bean.xml
ApplicationContext context = new ClasspathXmlApplicationContext("bean.xml");
//2.获取配置文件中所创建的对象
Person person = context.getBean("person",Person.class);//这里的input string就是bean.xml文件中自定义的bean id
//测试
System.out.println(person);
person.getProperties();
}
主体文件目录结构如下:
springExercise
├── HELP.md
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── springExercise.iml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── alibaba
│ │ │ └── springExercise
│ │ │ ├── Person.java
│ │ │ └── SpringExerciseApplication.java
│ │ └── resources
│ │ ├── application.properties
│ │ └── bean.xml
│ └── test
│ └── java
│ └── com
│ └── alibaba
│ └── springExercise
│ └── SpringExerciseApplicationTests.java
└── target
├── ...
...
29 directories, 19 files
二·IOC容器
1. 简单理解IOC概念
ioc:控制反转,举例说明:
在现实生活中,人们要用到一样东西的时候,第一反应就是去找到这件东西,比如想喝新鲜橙汁,在没有饮品店的日子里,最直观的做法就是:买果汁机、买橙子,然后准备开水。值得注意的是:这些都是你自己**“主动”创造**的过程,也就是说一杯橙汁需要你自己创造。
然而到了今时今日,由于饮品店的盛行,当我们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,通过电话等渠道描述你的需要、地址、联系方式等,下订单等待,过一会儿就会有人送来橙汁了。
"图和例子来源于"知乎链接
比如传统的两个类之间的关系,class B想要调用class A中的方法,那么首先要有一个class A的对象才可以供 B对象调用,现在则把这些过程统统交给spring处理。可以很好的降低耦合度。
2. IOC底层原理
主要用到:xml文件的解析、工厂设计模式、反射
2.1 发展背景
比如类user中想要调用person类中的add方法,那么需要先创建person对象,然后调用其方法。
------------------------------------------------------------------------
常见的可以处理上述问题的方法:使用工厂设计模式进行解耦
工厂模式对上述问题的耦合度的降低体现在:
1.对产品类(比如上述提到的class Person)的屏蔽,**不需要知道创建对象的过程,**产品类的实现如何变化,调用者无需关心,只需要关心产品的接口,接口只要保持不变,上层模块就不会变化。
工厂设计模式的其他优点:
1.良好的封装性,代码结构清晰,调用者只需知道产品的类名即可,不需要知道创建对象的过程,降低代码间的耦合。
2.扩展性优秀,如果增加一个产品类,只需增加一个对应的工厂类。
3.工厂模式是典型的解耦框架,高层模块只需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特法则,符合依赖倒置原则,符合里氏替换原则。
使用工厂模式降低两个类之间的耦合度(class A调用class B中的方法),但并不是最优的。IOC应用而生。
------------------------------------------------------------------------
总的来说,IOC的过程有三步。1.通过xml配置文件来配置要创建的对象。2.通过xml解析得到对应的class;3.通过反射来创建对象 4. 套用工厂模式的流程模版
2.2 IOC接口
- IOC思想基于IOC容器完成,IOC容器的底层实际上就是对象工厂。
- Spring中提供IOC容器的两种实现方式(两个接口),注意两者的不同:
(1) beanfactory: 是IOC容器的基本实现,属于Spring内部的使用接口,一般不提供开发人员使用。
beanfactory加载配置文件时不会创建对象,仅仅是加载.xml配置文件,只有在获取/使用时才会创建对应的对象。
(2) ApplicationContext: 是beanfactory的子接口,相比beanfactory来说提供了更多更强大的功能,一般面向开发人员使用。
ApplicationContext加载配置文件时就会创建配置文件中的对象。
ApplicationContext其中的两个实现类,其区别在于FileSystemXmlApplicationContext对应的是os中文件系统下的完整文件路径;
ClasspathXmlApplicationContext则对应的是当前文件目录中src文件夹。
2.3 IOC操作–Bean管理
2.3.1 基于xml配置文件方式实现Bean管理
- 基于xml配置文件方式创建对象
<bean id="person" class="com.alibaba.springExercise.Person">
<!-- <property name="name" value="spring"></property>-->
</bean>
id属性:给要创建的对象起一个别名或者其标识
class属性:要创建的对象所在类的全路径
name属性:与id属性一致,不过可以添加任意字符比如‘/’
利用上述xml文件创建对象时使用的是默认的无参构造函数。
**DI:依赖注入,实际上就是注入属性。 ****DI是IOC中的一个具体实现。**可以通过set()方法注入属性;也可以通过有参构造函数注入属性。
通过set()方法注入属性,首先在xml文件中的bean字段添加property属性,如下:
<bean id="person" class="com.alibaba.springExercise.Person">
<!--使用property来完成属性注入
name:类中定义的属性名称
value:该属性对应的值
-->
<property name="age" value="18"></property>
<property name="sex" value="man"></property>
</bean>
同时,在目标类中(Person class)中要添加set方法,否则会报错。
通过有参构造函数注入属性,在类中要添加有参构造器,其次就是在xml文件中的bean字段中添加constructor-args属性
<bean id="person" class="com.alibaba.springExercise.Person">
<constructor-arg index="0" value="28"></constructor-arg>
<constructor-arg index="1" value="woman"></constructor-arg>
</bean>
**
<!-- 首先加入限制 -->
xmlns:p="http://www.springframework.org/schema/p"
<bean id="person" class="com.alibaba.springExercise.Person" p:age="12" p:sex="man">
</bean>
- 字面量
(1)null值
<property name="age">
<null/>
</property>
(2)特殊符号
<!-- 使用CDATA结构 ![CDATA[]] -->
<property name="age">
<value><![CDATA[<<999>>]]></value>
</property>
- 注入bean(内部bean和外部bean及级联赋值)
使用场景:class A中调用class B的方法,那么class A中就需要先创建class B的对象,然后调用其方法
在xml文件中首先创建两个类的对象,比如user类和person类,然后在user类中注入person类对象属性,此时属性中
使用的是ref属性,并不是value属性,且ref属性的值就是所创建的person类的别名。
<!--外部bean-->
<bean id="user" class="com.alibaba.springExercise.User">
<property name="object" ref="person"></property>
</bean>
<bean id="person" class="com.alibaba.springExercise.Person"></bean>
<!--内部bean-->
<bean id="user" class="com.alibaba.springExercise.User">
<property name="object">
<bean id="person" class="com.alibaba.springExercise.Person">
</bean>
</property>
</bean>
- xml注入集合属性
注入数组类型属性; 注入List集合类型属性; 注入Map集合类型属性; 注入集合对象类型
首先创建类并创建对应属性字段,生成对应的set方法。
public class Employee {
private String[] courses;
private List<String> projects;
private Map<String, String> jobs;
private List<Course> learn;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setProjects(List<String> projects) {
this.projects = projects;
}
public void setJobs(Map<String, String> jobs) {
this.jobs = jobs;
}
public void setLearn(List<Course> learn) {
this.learn = learn;
}
public void test(){
System.out.println(Arrays.toString(courses));
System.out.println(projects);
System.out.println(jobs);
System.out.println(learn);
}
}
public class Course {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Course{" +
"name='" + name + '\'' +
'}';
}
}
然后在.xml文件中进行如下配置即可
<bean id="employee" class="com.alibaba.springExercise.collectionType.Employee">
<property name="courses">
<array>
<value>java</value>
<value>spring</value>
</array>
</property>
<property name="projects">
<list>
<value>xiaomi</value>
<value>aliyun</value>
</list>
</property>
<property name="jobs">
<map>
<entry key="开发" value="java"></entry>
<entry key="AI" value="python"></entry>
</map>
</property>
<property name="learn">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="com.alibaba.springExercise.collectionType.Course">
<property name="name" value="Spring框架"></property>
</bean>
<bean id="course2" class="com.alibaba.springExercise.collectionType.Course">
<property name="name" value="MyBatis框架"></property>
</bean>
最后进行测试
ApplicationContext context = new ClasspathXmlApplicationContext("bean.xml");
Employee employee = context.getBean("employee", Employee.class);
employee.test();
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util" <!--添加这句-->
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util <!--添加这句-->
http://www.springframework.org/schema/util/spring-util.xsd <!--添加这句-->
">
<util:list id="booklistlist">
<value>java</value>
<value>c++</value>
<value>python</value>
</util:list>
<bean id="book" class="com.alibaba.springExercise.collectionType.Book">
<property name="bookName" ref="booklistlist"></property>
</bean>
public class Book {
private List<String> bookName;
public void setBookName(List<String> bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookName=" + bookName +
'}';
}
public void test(){
System.out.println(bookName);
}
}
- IOC操作中Bean的方式
(1)普通Bean:就是上述所讲到的一些方式
(2)factorybean:
两者区别:普通Bean在配置文件中定义什么样的bean类型,返回的就是对应的类型;factorybean在配置文件中定义什么样的bean类型,返回的可以是和定义类型不一样。
如何定义一个factorybean?
step 1: 定义一个类让这个类作为factorybean,实现接口factorybean
step 2: 实现接口里面的方法,在实现的方法中定义返回的bean类型
<bean id="myBean" class="com.alibaba.springExercise.factorybean.Factory">
</bean>
public class Factory implements factorybean<Course> {
//定义返回bean
@Override
public Course getobject() throws Exception {
Course cou = new Course();
cou.setName("english");
return cou;
}
@Override
public Class<?> getobjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
//test
ApplicationContext context = new ClasspathXmlApplicationContext("bean1.xml");
Course myBean = context.getBean("myBean");
System.out.println(myBean);
- IOC操作中Bean的作用域
Spring的配置文件中可以配置创建单实例对象还是多实例对象。
判断单实例对象和多实例对象的标准:在测试文件中new多个同一bean对象,然后查看这多个相同bean对象的地址,如果地址一致,那么就是单实例,如果不一致就是多实例。
Spring配置文件中bean字段默认是创建单实例对象,可以通过bean字段中的scope属性来设置实例类型:
scope有三个值,第一个:默认不写,就是单实例子;第二个“singleton”单实例子 第三个“prototype” 多实例
**
singleton和prototype之间的区别:
- 一个是创建单实例,一个是创建多实例;
- 设置scope的值为singleton时,在加载spring配置文件时就会创建单实例对象;设置scope的值为prototype时,在加载spring配置文件时不会创建实例对象,而是在调用getBean方法时才会创建多实例对象。
- IOC操作中Bean的生命周期
bean的生命周期:1⃣️通过构造器创建bean实例2⃣️为bean设置属性值(通过set方法)3⃣️调用bean的初始化方法(需配置初始化方法,使用init-method属性)4⃣️得到bean对象5⃣️容器关闭时,调用bean的销毁方法(需要进行配置销毁的方法,使用destroy-Method属性)
还有一种是添加后置处理器的方式,其生命周期共有七步。
- IOC操作中Bean管理之xml自动装配
在bean字段中有autowrite属性,可以设置为byName和byType两种
(1)直接配置连接池方式, 借助druid包
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.MysqL.jdbc.Driver"></property>
<property name="url" value="jdbc:MysqL://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
(2)创建外部属性文件,properties格式文件,写数据库信息:
prop.driverClassName=com.MysqL.jdbc.Driver
prop.url=jdbc:MysqL://localhost:3306/userDb
prop.username=root
prop.password=root
把外部properties属性文件引入到spring配置文件中
首先在配置文件中声明一个context名称空间,然后在spring配置文件中使用标签引入外部属性文件。
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClassName}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
2.3.2 基于注解方式实现Bean管理
目的:简化xml配置
- 基于注解方式创建对象
Spring中针对Bean管理中创建对象提供的注解有:@Component @Service @Controller @Repository
四个注解的功能一样,都可创建bean实例。
step1:引入AOP依赖(在pom.xml文件中)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.8</version>
</dependency>
step2:开启组件扫描,目的是为了让编译器知道该扫描哪个类从而找到对应的注解。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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
">
<!--
开启组件扫描:
1.如果扫描多个包,可以使用","隔开
2.扫描包上层目录
-->
<context:component-scan base-package="com.alibaba.springExercise.annotation"></context:component-scan>
</beans>
@Component(value = "createShop")
public class Shop {
public void add(){
System.out.println("Annotation add .....");
}
}
@Test
public void test1(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean2.xml");
Shop createShop = context.getBean("createShop",Shop.class);
createShop.add();
}
组件扫描配置
<!--更加精细化的扫描
只扫描annotation包下带注解@Component的类(先把use-default-filters置为false)
-->
<context:component-scan base-package="com.alibaba.springExercise.annotation" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Component"/>
</context:component-scan>
<!--设置不去扫描包下带有@Component的类-->
<context:component-scan base-package="com.alibaba.springExercise.annotation">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Component"/>
</context:component-scan>
**
- 基于注解方式注入属性
@AutoWired: 根据属性类型进行自动装配
@Qualifier:根据属性名称进行注入
@Qualifier注解的使用要和@AutoWired注解配合使用
@Resource:可以根据属性类型注入,也可以根据名称注入
@Value: 为类的属性注入值
@Controller(value = "userDaoImpltest")
public class UserDaoImpl implements UserDao{
@Override
public void sayHello() {
System.out.println("UserDaoImpl running......");
}
}
//---------------------------
//默认值是类名称,首字母小写
@Component(value = "createShop")
public class Shop {
@Autowired
@Qualifier(value = "userDaoImpltest")
private UserDao userDao;
@Value(value = "tianmao")
private String name;
public void add(){
System.out.println("Annotation add ....."+name);
userDao.sayHello();
}
}
//---------------------------
@Test
public void test2(){
ApplicationContext context = new ClasspathXmlApplicationContext("bean2.xml");
Shop shop = context.getBean("createShop",Shop.class);
shop.add();
}
- ** 完全注解开发(不用xml配置文件进行配置)**
//创建配置类,替代xml配置文件
@Configuration
@ComponentScan(basePackages = {"com.alibaba.springExercise.annotation"})
public class SpringConfig {
}
//----------
//默认值是类名称,首字母小写
@Component(value = "createShop")
public class Shop {
@Autowired
@Qualifier(value = "userDaoImpltest")
private UserDao userDao;
@Value(value = "tianmao")
private String name;
public void add(){
System.out.println("Annotation add ....."+name);
userDao.sayHello();
}
}
//----------
@Test
public void test3(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Shop createShop = context.getBean("createShop", Shop.class);
createShop.add();
}
三. AOP
1.AOP基本概念
面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的重用性,同时提高了开发效率。
举例理解AOP:比如设计一个登陆功能模块,正常流程:先输入用户名和密码,然后进行数据库查询,接着进行判断,如果用户存在且密码正确则进入主页面,否则返回登陆界面。
假设现在需要添加一个新的功能,比如要判断一下用户权限,是普通用户还是管理员用户。原始方式:通过直接在源代码上进行修改,添加ifelse判断来进行;AOP方式则是把权限判断功能作为一个独立的模块,通过进行某些配置从而使源代码具有权限判断的功能。也就是说AOP可以通过不修改源代码的方式添加新的功能。
2.AOP底层原理
2.1 AOP底层使用动态代理
(1)有两种情况进行动态代理
第一种:有接口情况,使用JDK动态代理
第二种:无接口情况,使用cglib动态代理
2.2 AOP(JDK动态代理方式源码实践)
参数一:类加载器来定义代理类
参数二:增强方法所在的类,这个类实现的接口,支持多个接口
参数三:实现这个接口InvocationHandler,创建代理对象,写增强的方法
//==========================Agent接口
public interface Agent {
public int add(int a,int b);
public void update(String str);
}
//==========================AgentImpl:Agent接口的实现类
public class AgentImpl implements Agent{
@Override
public int add(int a, int b) {
System.out.println("正在执行add方法");
return a+b;
}
@Override
public void update(String str) {
System.out.println("String已经更新");
}
}
//==========================使用Proxy类创建接口代理对象
public class JDKProxyTest {
public static void main(String[] args) {
//创建接口类的代理对象
Class[] interfaces = {Agent.class};
AgentImpl agentImpl = new AgentImpl();
Agent getProxy =(Agent) Proxy.newProxyInstance(JDKProxyTest.class.getClassLoader(), interfaces, new AgentProxy(agentImpl));
int add = getProxy.add(1, 2);
System.out.println("result:"+add);
getProxy.update("updateStr");
}
}
class AgentProxy implements InvocationHandler{
//1.把要创建的目标接口/类的代理对象的目标/类先传递过来
//有参数构造进行传递
private Object object;
public AgentProxy(Object obj){
this.object = obj;
}
//2.增强/补充的逻辑
//对被代理对象的每个方法执行前后均执行sout相关操作
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行:"+method.getName()+"传递的参数是:"+ Arrays.toString(args));
Object res = method.invoke(object, args);
System.out.println("方法之后执行"+object);
return res;
}
}
2.3 AOP部分术语
- 连接点:在一个类中,可以被增强的方法叫做连接点,比如上述AgentImpl类中的add方法就是一个连接点
- 切入点:连接点是可以被增强的,而切入点指的是实际被增强的,比如上述AgentImpl类有两个方法,假设我们只增强update方法,那么update方法就是一个切入点。
- 通知/增强:实际增强的逻辑部分叫做通知。比如上述demo中在方法的前后加了两句sout语句,这两句sout语句就叫做通知/增强。
通知有多种类型:前置通知(方法前执行)/后置通知(方法后执行)/环绕通知(方法前后都执行)/异常通知(方法异常才执行)/最终通知(类似于try-catch-finally中的finally)
- 切面:把通知应用到切入点的动作/过程叫做切面
2.4 AOP操作
2.4.1 准备
Spring框架一般是基于AspectJ实现AOP操作。(AspectJ不是Spring组成部分,是一个独立的AOP框架,一般把AspectJ和Spring一起使用)。
基于AspectJ实现AOP操作有(1)基于xml配置文件实现(2)基于注解方式实现(一般使用这种方式)。
在项目工程中引入AOP相关依赖。
切入点表达式:其作用是知道对哪个类里面的哪个方法进行增强;其语法规则为:
execution([权限修饰符][返回类型][类全路径]方法名称)
eg: execution(*com.alibaba.springExercise.aopLearn.AgentImpl.update(…));
eg: execution(com.alibaba.springExercise.aopLearn.AgentImpl.(…));
加入一些依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.8</version>
</dependency>
2.4.2 基于AspectJ注解方式实现AOP操作
//-----------------1.定义一个被增强类,定义相应方法
//被增强类
@Component(value = "school")
public class School {
public void add(){
System.out.println("School class add a new person.");
}
}
//-----------------2.定义一个增强类,定义增强的方法/也就是通知的逻辑代码
@Component(value = "schoolimprove")
@Aspect //在增强类上添加该注解,生成代理对象
public class SchoolImprove {
//前置通知
//@Before注解表示作为前置通知
@Before(value = "execution(* com.alibaba.springExercise.aopExercise.School.add(..))")
public void before(){
System.out.println("before..........");
}
//@After @AfterReturning @AfterThrowing
@Around(value = "execution(* com.alibaba.springExercise.aopExercise.School.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("before..........");
proceedingJoinPoint.proceed();
System.out.println("after..........");
}
}
//-----------------3.进行通知的配置
//(1)首先在spring文件中开启注解扫描(通过xml方式/创建配置类的方式)
//(2)使用注解创建School和SchoolImprove对象(见上)
//(3)在增强类上面添加注解@Aspect (见上)
//(4)Spring配置文件中开启生成代理对象的功能
//创建配置类,替代xml配置文件
@Configuration
@ComponentScan(basePackages = {"com.alibaba.springExercise.aopExercise"})
@EnableAspectJAutoproxy(proxyTargetClass = true)//开启生成代理对象的功能
public class SpringConfig {
}
/*
//xml配置文件格式
<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"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--
开启组件扫描:
1⃣️如果扫描多个包,可以使用","隔开
2⃣️扫描包上层目录
-->
<context:component-scan base-package="com.alibaba.springExercise.aopExercise"></context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
*/
//-----------------4.配置不同类型的通知
//在增强类的作为通知的方法上添加通知类型注解,并使用切入点表达式进行配置
//比如下述这样
/*
//前置通知
//@Before注解表示作为前置通知
@Before(value = "execution(* com.alibaba.springExercise.aopExercise.School.add(..))")
*/
//-----------------Test
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// ApplicationContext context = new ClasspathXmlApplicationContext("beanaop.xml");
School school = (School) context.getBean("school");
school.add();
}
一些tricks:
@pointcut(value = "execution(* com.alibaba.springExercise.aopExercise.School.add(..)")
public void pointcutDemo(){
}
- 假设目前有多个增强类对目标类进行增强,此时就需要设置一下增强类的优先级
2.4.3 基于AspectJ的xml配置文件方式实现AOP操作
这里不赘述了,了解即可,需要用到再回顾即可。