Spring核心讲解

1、Spring框架概述

  • Spring是轻量级的开源的JavaEE框架

  • Spring可以解决企业应用开发的复杂性

  • Spring有许多组成部分 核心IOC和AOP

  • IOC:控制反转 把创建对象的过程交给Spring进行管理

  • AOP: 面向切面 不修改源代码进行功能增强

  1. 方便解耦 简便开发
  2. AOP编程支持
  3. 方便unit测试
  4. 可以方便和其他框架进行集合
  5. 支持事务处理以及降低API的开发难度

2、入门案例

1、下载Spring5

2、选择地址进行下载

3、复制这个地址

下载地址https://repo.spring.io/ui/native/release/org/springframework/spring

4、源码解压

JAR包分为三类:

  • .jar基本jar包
  • .javadoc 文档包
  • .source源代码包

这里我们主要研究四个

  • Beans 对应IOC
  • Core 对应IOC
  • Context 对应上下文
  • Expression 对应表达式

5、JAR包导入

6、使用Spring方式创建对象

6.1 测试 使用普通类进行创建对象

/*** @author* @Package com.ljx.spring5* @date 2021-09-14 15:26*/
public class User {public void add(){System.out.println("add....");}
}
User user = new User();

6.2 使用Spring方式创建

1.通过配置文件 在配置文件里面创建对象

<?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">
<!--  配置User创建  --><bean id="user" class="com.ljx.spring5.User"></bean>
</beans>

通过这个bean实现了对象的创建

2、测试对象的编写

package com.ljx.test;import com.ljx.spring5.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author ljx* @Package com.ljx.test* @date 2021-09-14 15:45*/
public class TestSpring5 {@Testpublic void test01(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean1.xml");//获取配置创建的对象  这个user是对应的bean的IdUser user = applicationContext.getBean("user", User.class);System.out.println(user);}}

测试Spring创建对象

3、IOC容器

3.1、IOC底层原理

1、什么是IOC

  • 控制反转也可以被称为依赖注入,把对象创建和对象之间的调用过程交给Spring进行管理

  • 为什么使用:为了降低耦合度

  • 上面的案例就是IOC的实现

2、IOC底层原理

(1)xml解析、工厂模式、反射

原始创建对象的方式

使用IOC的过程

3、IOC接口

1、IOC思想基于IOC容器,IOC容器底层就是对象工厂

2、Spring提供了两种方式

  • BeanFactory: IOC最基本的实现方式 是Spring 内部使用的接口 不提供开发使用

加载配置文件的时候是不会创建对象,只有获取对象才会去创建对象

  • ApplicationContext:BeanFactory接口的子接口 一般是由开发人员进行使用的

加载配置文件的时候 就会把对象给创建出来

3、ApplicationContext实现类

  • FileSystemXmlApplicationContext 指的是配置文件的带盘符的路径
  • ClassPathXmlApplicationContext 指的是配置文件的类路径 也就是src的路径

4、BeanFactory接口实现类

3.2、IOC接口(BeanFactory)

IOC操作Bean管理

1、Bean管理

  • Spring创建对象
  • Spring属性注入

2、Bean管理的两种操作方式

(1) 基于xml配置文件的方式进行注入

(2)使用注解的方式进行注入

3、基于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">
<!--  配置User创建  -->
<!--  bean的属性讲解id: 给一个对象起一个表示  根据这个表示可以获取对象class:属性 类的全路径-->
<!-- 没有设置参数的时候默认会执行无参的构建   --><bean id="user" class="com.ljx.spring5.User"></bean>
<!--  基于XML的方式注入属性1、DI 依赖注入 就是注入属性  是IOC的一种具体实现  前提是在对象已经创建的基础上
-->
</beans>

3.3、IOC的Bean管理(基于XML)

1、在配置文件中先实现对象创建

2、注入属性

通过set方法注入

<?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">
<!--  配置User创建  -->
<!--  bean的属性讲解id: 给一个对象起一个表示  根据这个表示可以获取对象class:属性 类的全路径-->
<!-- 没有设置参数的时候默认会执行无参的构建   --><bean id="user" class="com.ljx.spring5.User"><property name="userName" value="ljx"/></bean>
<!--  基于XML的方式注入属性1、DI 依赖注入 就是注入属性  是IOC的一种具体实现  前提是在对象已经创建的基础上
name 是属性名称  value是设置的值
-->
</beans>
前提是对象里面要有Set方法  注入属性就相当于设置对应的Set方法

编写对应的测试类

 @Testpublic void test02(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径BeanFactory applicationContext=new ClassPathXmlApplicationContext("bean1.xml");//获取配置创建的对象  这个user是对应的bean的IdUser user = applicationContext.getBean("user", User.class);String userName = user.getUserName();System.out.println(userName);}

通过构造方法注入

<?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">
<!--  配置User创建  -->
<!--  bean的属性讲解id: 给一个对象起一个表示  根据这个表示可以获取对象class:属性 类的全路径-->
<!-- 没有设置参数的时候默认会执行无参的构建   --><bean id="user" class="com.ljx.spring5.User">
<!--        <property name="userName" value="ljx"/>--><constructor-arg name="userName" value="ljx"/></bean>
<!--  基于XML的方式注入属性1、DI 依赖注入 就是注入属性  是IOC的一种具体实现  前提是在对象已经创建的基础上
-->
</beans>

编写对应测试类

@Testpublic void test02(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径BeanFactory applicationContext=new ClassPathXmlApplicationContext("bean1.xml");//获取配置创建的对象  这个user是对应的bean的IdUser user = applicationContext.getBean("user", User.class);String userName = user.getUserName();System.out.println(userName);}

注入其他类型的属性

<?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"><!--  配置User创建  --><!--  bean的属性讲解id: 给一个对象起一个表示  根据这个表示可以获取对象class:属性 类的全路径--><!-- 没有设置参数的时候默认会执行无参的构建   --><bean id="user" class="com.ljx.spring5.User"><property name="userName" value="李加喜"/><property name="address"><!--    为属性设置空值        --><null/></property><!--   属性值设置了特殊符号     --><!--        <constructor-arg name="userName" value="李加喜"/>--><property name="userId"><value><![CDATA[<<用户Id]>>]]></value></property></bean><!--  基于XML的方式注入属性1、DI 依赖注入 就是注入属性  是IOC的一种具体实现  前提是在对象已经创建的基础上-->
</beans>

注入属性-外部bean

创建dao和daoImpl

public interface UserDao {/*** 修改*/void update();
}
public class UserDaoImpl implements UserDao {@Overridepublic void update() {System.out.println("service add ....");}
}

创建service里面引入dao

public class UserService {// 创建UserDao类型的属性  生成对应的Set方法private UserDao userDao1;public UserDao getUserDao1() {return userDao1;}public void setUserDao1(UserDao userDao1) {this.userDao1 = userDao1;}public void add(){System.out.println("测试 add...");userDao1.update();}
}

配置文件里面进行引入

<?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"><!--  创建service和dao对象  --><bean id="userService" class="com.ljx.service.UserService"><!--   name是属性的名字  res是类里面属性的名称     --><property name="userDao1" ref="userDao"/></bean><!----这里引入的是接口的实现类接口是不允许进行实例化的----!><bean id="userDao" class="com.ljx.dao.UserDaoImpl"/>
</beans>

FactoryBean

Spring里面有两种Bean 一种普通的一种工厂Bean(FactoryBean)

  • 普通Bean定义的类型就是自己定义的类型
  • 工厂Bean 在配置文件里面定义的bean类型可以和返回类型不一样

第一步:创建一个类 让这个类作为工厂bean 实现接口FactoryBean

第二步:实现接口里面的方法 在实现的方法中定义返回的bean类型

package com.ljx.factorybean;import com.ljx.spring5.User;
import org.springframework.beans.factory.FactoryBean;/*** @author* @Package com.ljx.factorybean* @date 2021-09-16 15:08*/
public class MyBean implements FactoryBean<User> {/*** 定义返回的Bean* @return* @throws Exception*/@Overridepublic User getObject() throws Exception {User user = new User();user.setUserName("ljx");return user;}@Overridepublic Class<?> getObjectType() {return null;}
}

配置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"><bean id="myBean" class="com.ljx.factorybean.MyBean"></bean>
</beans>

编写测试类

@Testpublic void testCollection() {// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径BeanFactory applicationContext = new ClassPathXmlApplicationContext("bean3.xml");//获取配置创建的对象  这个user是对应的bean的IdUser myBean = applicationContext.getBean("myBean", User.class);System.out.println(myBean);}

bean的作用域

可以设置 bean是单实例还是多实例

Spring默认是单实例

@Testpublic void testBook(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径BeanFactory applicationContext = new ClassPathXmlApplicationContext("bean3.xml");//获取配置创建的对象  这个user是对应的bean的IdBook book = applicationContext.getBean("book", Book.class);System.out.println(book);Book book1 = applicationContext.getBean("book", Book.class);System.out.println(book.equals(book1));}

返回结果是true 所以默认是单实例的

设置对象是多实例对象

设置配置文件

<?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="myBean" class="com.ljx.factorybean.MyBean"></bean><bean id="book" class="com.ljx.factorybean.Book" scope="prototype"></bean>
</beans>
prototype:是多实例
singleton:是单实例

编写测试文件

@Testpublic void testBook(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径BeanFactory applicationContext = new ClassPathXmlApplicationContext("bean3.xml");//获取配置创建的对象  这个user是对应的bean的IdBook book = applicationContext.getBean("book", Book.class);System.out.println(book);Book book1 = applicationContext.getBean("book", Book.class);System.out.println(book.equals(book1));}
是false  说明当前是多实例的

bean的生命周期

1、生命周期

从对象的创建到对象的销毁的过程

2、bean的生命周期

  • 通过构造器创建bean的实例(无参构造)
  • 为bean的属性设置值和对其他bean进行引用(调用set方法)
  • 调用bean的初始化方法
  • bean可以进行获取了
  • 当容器管理之后 调用bean的销毁方法
package com.ljx.bean;/*** @author 李加喜* @Package com.ljx.bean* @date 2021-09-16 21:48*/
public class Orders {private String name;public String getName() {return name;}public void setName(String name) {System.out.println("第二步 调用set设置值");this.name = name;}public Orders(String name) {this.name = name;}public Orders(){System.out.println("第一步 执行无参数构造 构造创建bean");}// 创建初始化方法public void initMethod(){System.out.println("第三步调用自定义初始化方法");}/*** 执行销毁方法*/public void destroyMethod(){System.out.println("第五步 调用销毁方法");}
}

编配配置文件

<?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="orders" class="com.ljx.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"><property name="name" value="名称"/></bean>
</beans>

测试

@Testpublic void testOrders(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean4.xml");//获取配置创建的对象  这个user是对应的bean的IdOrders orders = applicationContext.getBean("orders", Orders.class);System.out.println("第四步 获取bean实例对象");System.out.println(orders);// 手动销毁applicationContext.close();}
结果
第一步 执行无参数构造 构造创建bean
第二步 调用set设置值
第三步调用自定义初始化方法
第四步 获取bean实例对象
com.ljx.bean.Orders@64f6106c
第五步 调用销毁方法

3、bean的后置处理器 (总共七步)

  • 通过构造器创建bean的实例(无参构造)
  • 为bean的属性设置值和对其他bean进行引用(调用set方法)
  • 将bean的实例传递给后置处理器(postProcessBeforeInitialization)
  • 调用bean的初始化方法
  • 将bean的实例传递给后置处理器(postProcessAfterInitialization)
  • bean可以进行获取了
  • 当容器管理之后 调用bean的销毁方法

创建类 实现接口BeanPostProcessor 创建后置处理器

public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("初始化之前 postProcessBeforeInitialization");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("初始化之后postProcessAfterInitialization");return 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="orders" class="com.ljx.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"><property name="name" value="名称"/></bean><bean id="beanPost" class="com.ljx.bean.MyBeanPost"></bean>
</beans>

这样容器里面的所有Bean都会执行这个方法

基于xml的自动装配

  1. 根据指定的装配规则(属性名称/属性类型) Spring自动将匹配的属性值进行注入
<?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="orders" class="com.ljx.bean.Orders" init-method="initMethod"destroy-method="destroyMethod"><property name="name" value="名称"/></bean><bean id="beanPost" class="com.ljx.bean.MyBeanPost"></bean><!-- byName 根据属性名进行注入  注入的值的bean的id要和类的属性名称一致byType 根据类型进行注入  找到属性的类型在管理的对象里面进行注入 注意 如果出现相同类型的两个bean 就会出去错误 --><bean id="emp" class="com.ljx.bean.Emp" autowire="byName"><!--        <property name="dept" ref="dept"/>--></bean><bean id="dept" class="com.ljx.bean.Dept"></bean>
</beans>

类型

package com.ljx.bean;import java.util.Date;/*** @author 李加喜* @Package com.ljx.bean* @date 2021-09-16 22:59*/
public class Emp {private Dept dept;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return "Emp{" +"dept=" + dept +'}';}public  void test(){System.out.println(dept);}
}public class Dept {@Overridepublic String toString() {return "Dept{}";}}
package com.ljx.bean;import java.util.Date;/*** @author 李加喜* @Package com.ljx.bean* @date 2021-09-16 22:59*/
public class Emp {private Dept dept;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return "Emp{" +"dept=" + dept +'}';}public  void test(){System.out.println(dept);}
}public class Dept {@Overridepublic String toString() {return "Dept{}";}}

3.4、IOC的Bean管理()基于注解

1、创建对象提供的注解

  • @Service

  • @Component

  • @Controller

  • @Reposibility

上面的四个注解都可以用来创建bean实例

2、基于注解实现对象的创建

第一步、引入依赖

spring-aop-5.2.6.RELEASE.jar引入这个jar包

第二步、开启组件扫描

<?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"><bean id="dept" class="com.ljx.bean.Dept"></bean><!--    开启组件扫描       --><context:component-scan base-package="com.ljx"/>
</beans>

第三步 创建类 在类上面添加创建对象的注解

@Component(value="可以是自定义名称 默认是类的首字母小写")
public class Pfm {public void add(){System.out.println("add");}
}

第四步 测试

@Testpublic void pfm(){// 加载Spring的配置文件  在src下直接写名称 不在的话需要写具体路径ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean4.xml");//获取配置创建的对象  这个user是对应的bean的IdPfm pfm = applicationContext.getBean("pfm", Pfm.class);pfm.add();}

3、组件扫描的细节配置

<!--    开启组件扫描--><context:component-scan base-package="com.ljx"/>
<!--  use-default-filters="false" 表示不使用默认的filter 自己配置filtercontext:include-filter  设置需要扫描那些配置类  这类的配置只会扫描带有Controller的类
--><context:component-scan base-package="com.ljx" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/></context:component-scan>
<!--只扫描包含Component的类--><context:component-scan base-package="com.ljx" ><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/></context:component-scan>

4、基于注解的方式实现属性注入

1、@AutoWired 根据类型进行注入

2、@Qualifier 根据属性名称注入

3、@Resource 可以根据类型也可以根据名称

4、@Value 根据普通类型注入

public interface UserDao {/*** 修改*/void update();
}
@Repository
public class UserDaoImpl implements UserDao {@Overridepublic void update() {System.out.println("service add ....");}
}
@Service
public class UserService {@Autowiredprivate UserDao userDao;public void add(){System.out.println("测试 add...");userDao.update();}
}@Testpublic void setUserService(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean5.xml");//获取配置创建的对象  这个user是对应的bean的IdUserService userService = applicationContext.getBean("userService", UserService.class);userService.add();}

开启组件扫描

<?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">
<!--    开启组件扫描--><context:component-scan base-package="com.ljx"/>
</beans>

使用@Qualifier指定名称注入 防止接口有多个实现类

@Repository(value = "userDao1")
public class UserDaoImpl implements UserDao {@Overridepublic void update() {System.out.println("service add ....");}
}
@Service
public class UserService {//@Autowired@Qualifier(value = "userDao1")private UserDao userDao;public void add(){System.out.println("测试 add...");userDao.update();}
}

完全注解开发

1、配置类

@Configuration
@ComponentScan(basePackages = {"com.ljx"})
public class SpringConfig {}
取代了xml注解

2、测试

@Testpublic void config(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService = context.getBean("userService", UserService.class);userService.add();}

4、AOP

  • 面向切面编程(面向方面编程)

  • 降低耦合度 提高开发

  • 主要就是方便在已有的功能上面添加新的功能 降低代码的耦合度

AOP底层使用的动态代理的方式进行实现的

  • 有接口的动态代码 JDK的动态代理

  • 没有接口的动态代理 CGLIB动态代理

1、创建Interface接口和接口的实现类

public interface UserDao {public Integer add(int a,int b);public void update(String id);
}
public class UserDaoImpl implements UserDao {@Overridepublic Integer add(int a, int b) {return a+b;}@Overridepublic void update(String id) {System.out.println(id);}
}
public class JDKProxy {public static void main(String[] args) {UserDaoImpl userDao = new UserDaoImpl();// 创建接口实现类的代理对象Class[] interfaces = {UserDao.class};UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,new UserDaoProxy(userDao));Integer add = dao.add(1, 2);System.out.println(add);}
}class UserDaoProxy implements InvocationHandler {// 需要把谁的代理对象要把 对象传递过来private Object object;public UserDaoProxy(Object object){this.object=object;}// 增强逻辑@Overridepublic 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(res);// 方法之后System.out.println("方法之后执行"+object);return res;}
}
结果
方法之前执行add传递的参数是[1, 2]
3
方法之后执行com.ljx.UserDaoImpl@355da254
3

AOP专业术语

  • 连接点 类里面那些方法可以被增强 方法被称为连接点

  • 切入点 实际被增强的方法

  • 通知(增强) 实际增强的逻辑部分就是通知(前置 后置 环绕 异常 最终)

  • 切面 将通知应用到切入点的过程

2、AOP的JDK动态代理案例

使用newProxyInstance方法,方法有三个参数 (类加载器、增强方法所在的类 这个类所在的接口 支持多个接口、实现InvocationHandle接口 创建代理对象写增强方法)

3、Spring框架基本使用Aspectj实现AOP操作

一般和Spring框架一起使用实现Aop的功能 一般开发中是基于注解的方式进行使用

4、在项目中引入AOP的依赖

5、切入点的表达式

语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])

execution(*com.ljx.dao.BookDao.add(…))

execution(*com.ljx.dao.BookDao. * (…)) BookDao下面的左右方法

execution(*com.ljx.dao. * . * (…)) 下面的所有的方法

6、使用注解的方式实现Aop

在增强类里面创建方法 让不同的代表不同的通知类型

  • 开启注解扫描
  • 使用注解创建User和UserProxy
  • 在增强类上面添加注解@Aspect
  • 在Spring配置文件中开启生成代理对象
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd
"><context:component-scan base-package="com.ljx"/><!--    开启Aspect生成代理对象  扫描的类上面有@Aspect就生成代理对象--><aop:aspectj-autoproxy/>
</beans>

设置类

// 被增强类
@Component
public class User {public void add() {System.out.println("add...");}
}
@Component
@Aspect
public class UserProxy {// 在public void before() {System.out.println("before");}
}

配置不同类型的通知

在增强类里面在作为通知类型的注解使用切入点表达式配置

package com.ljx.aopanno;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;// 前置通知 增强类
@Component
@Aspect
public class UserProxy {/*** 相同切入点抽取*/@Pointcut(value = "execution(* com.ljx.aopanno.User.add(..))")public void pointDemo(){}/*** 前置通知*/@Before(value = "pointDemo()")public void before() {System.out.println("before");}/*** 后置通知*/@After(value = "pointDemo()")public void after(){System.out.println("after");}/*** 返回值之后执行*/@AfterReturning(value = "pointDemo()")public void afterReturning(){System.out.println("afterReturning");}/*** 出现异常的时候进行通知*/@AfterThrowing(value = "pointDemo()")public void afterThrowing(){System.out.println("afterThrowing");}/*** 环绕通知*/@Around(value = "pointDemo()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("around前");// 执行增强的方法proceedingJoinPoint.proceed();System.out.println("around后");return new Object();}
}

有多个增强类对同一个方法进行增强 设置优先级

在增强类里面添加注解**@Order**(数字类型的值) 数字类型值越小优先级越高

5、事务操作

事务是数据库操作最基本的单元 逻辑上的一组操作 要么都成功要么都失败

四大特性: ACID

  • 原子性 要么都成功呢要么都失败
  • 一致性 操作前后数据不变
  • 隔离性 多事务操作的时候不会产生影响
  • 持久性 表中数据真正发生改变

事务的操作

基本使用的声明式事务(基于AOP的)

事务的传播行为:

  • 多事务方法直接进行调用,这个过程中事务是如何进行管理的
  • REQUIRED 如果事务在运行 当前方法就在这个事务内运行 否则就启动一个新的事务
  • REQUIRED_NEW 当前的方法必须启动新的事务 并在他自己的事务内运行 如果有事务正在运行 应该将他挂起
  • SUPPORTS 如果事务在运行 当前的方法就在这个事务内运行 否则可以不运行在事务内
  • NOT_SUPPORTS 当前方法不应该在事务中运行 如果有运行的事务 将他挂起
  • MANDATORY 当前的方法必须运行在事务内部 如果没有正在运行的事务 就抛出异常
  • NEVER 当前的方法不应该运行在事务中 如果有运行的事务 就抛出异常
  • NESTED 如果有事务在运行 当前的方法就应该在这个事务的嵌套事内运行 否则就启动一个新的事务

事务隔离级别:

  • 多事务之间不会产生影响 不考虑隔离性产生很多问题 比如
  • 脏读:多个事务之间一个未提交的事务获取了另一个未提交的事务数据

举例:A将数据从1改为2 不进行读取的时候获取的是2 但是这个时候A进行了回滚 那么B读的数据就是脏数据

  • 不可重复读:一个未提交的事务读取了另一个事务修改的数据

A和B都在读取数据 A将数据从100改为200 然后事务进行了提交 但是B在读取数据的时候没有提交数据 导致B一致获取的A提交的数据 导致可能每一次读取的数据都会发生改变

  • 幻读 一个未提交的事务获取了另一个提交事务的数据

设置事务隔离级别

  • READ UNCOMMITTED(读未提交) 脏读 不可重复读 幻读
  • READ COMMINTED(读已提交) 不可重复读 幻读
  • READATABLE READ(可重复度) 幻读
  • SERIALIZABLE(串行化)

Spring原码讲解相关推荐

  1. Spring源码讲解之 getBean 方法

    getBean 方法是用来进行获取 bean 实例对象的,是我们进行 spring 程序开发从 bean 工厂获取结果的.那这个方法的执行过程是什么样的,下面我们就去揭开它的面纱. 样例代码 Appl ...

  2. Spring 源码讲解:bean 的创建流程 - 公开课笔记

    Spring 官网所有版本下载 官网文档中的链接找起来比较麻烦.我们可以通过下面这个链接: https://repo.spring.io/release/org/springframework/spr ...

  3. 原码、反码、补码知识详细讲解(此作者是我找到的讲的最细最明白的一个)

    本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希 ...

  4. python基础运算符讲解(原码、补码、反码)

    Python 1.Python基础 python是一门弱类型(PHP,python,Javascript,ruby)的语言,变量的类型不固定,当输入值是什么类型时,变量就会变成什么类型. 那什么是强数 ...

  5. (原码、反码和补码)例子byte的详细讲解

    <此处转载> 1.原码.反码和补码定义 1.原码 将最高位作为符号位(以0代表正,1代表负),其余各位代表数值本身的绝对值(以二进制表示). 为了简单起见,我们用1个字节来表示一个整数. ...

  6. JavaSE笔记(09) —— 进制之间的转换以及原码,反码,补码的讲解

    进制的介绍 对于整数,有四种表示方式: 二进制:0,1 ,满 2 进 1.以 0b 或 0B 开头: 十进制:0-9 ,满 10 进 1: 八进制:0-7 ,满 8 进 1. 以数字 0 开头表示: ...

  7. 数据结构与算法--二进制详解 Python二进制算法详解 史上最详细的二进制讲解 彻底搞懂原码、反码、补码 Python的负数二进制表示形式

    阅读目录 原码.反码.补码 机器数 和 真值 原码.反码.补码的基础 Python中负数的处理 负数的补码如何转成十进制 位运算符 和 移位运算符 基本概述 妙用 二进制涉及的算法 原码.反码.补码 ...

  8. Spring源码深度解析(郝佳)-学习-Spring Boot体系原理

      Spring Boot是由Pivotal团队提供的全新框架,其设计目的用来简化新Spring应用初始化搭建以及开发过程,该框架使用了我写的方式进行配置,从而开发人员不再需要定义样板化的配置,通过这 ...

  9. spring源码扩展点与实战(二)

    在上一篇文章<spring源码扩展点>,我们简单的介绍了 spring 的几个常用扩展点,了解了 BeanPostProcessor, BeanFactoryPostProcessor, ...

最新文章

  1. 豆瓣评分9.4,跪着推荐这本密码学入门第一书
  2. Java-P: 2_3,类成员具有的控制修饰符
  3. python和java哪个-Python和Java两门编程语言,学习哪个更好?
  4. 树莓派进阶之路 (009) - 树莓派ftp脚本(原创)
  5. VS.NET 2005真是太好用了!
  6. 斗地主案例的需求分析
  7. 大数据量生成工具源代码(Delphi)
  8. graph driver-device mapper-04libdevmapper基本操作
  9. codeforces 842 D. Vitya and Strange Lesson(01字典树+思维+贪心)
  10. Orleans 知多少 | 2. 核心概念一览
  11. php 做更新进度条,PHP exec()后更新Bootstrap进度条
  12. DHCP服务器--红色箭头
  13. 用websocket技术开发的web聊天系统
  14. 表单设置默认值_你还不知道表单怎么设计吗?看这里!
  15. web前端基础(08html5新标签)
  16. vscode快捷键:多行同时输入
  17. matlab表格三维柱状图,excel制作四维数据表格-excel三维柱形图 ,请问如何根据excel表格中的数据......
  18. 【转】UML的9种图例解析
  19. 分享一个外泌体数据库
  20. vue 引入萤石视频

热门文章

  1. WordPress主题下载Sparkling个人简洁博客主题
  2. 盟军敢死队开发工具箱
  3. R语言使用as.Date函数把dataframe中的多个数据列(multiple columns)从字符串转化到日期类型
  4. python的pptx库_python学习之python-pptx
  5. Skynet基础入门例子详解(7)
  6. 解决win + R 键运行窗口中无历史记录
  7. element表格中的合并行或列
  8. alfafile中转站免费_中转站全集免费在线观看-手机看中转站HD完整版 - 穷TV_院线大片影视大全...
  9. qt android 中文乱码,Qt与MSVC中文乱码问题的解决方案
  10. Linux之配置Yum软件仓库