1、Spring简介
官网: https://spring.io/
1.1 什么是框架
- 源自于建筑学,隶属土木工程,后发展到软件工程领域
- 软件工程框架:经过验证的,具有一定功能的,半成品软件
- 经过验证
- 具有一定功能
- 半成品
1.2 框架的作用
1.3 Spring是什么
Spring是分层的JavaSE/EE应用full-stack轻量级开源框架
1.4 Spring的体系结构
2、IOC容器
- IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源
- Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器
2.1 spring入门
2.1.1依赖
buildscript {
repositories {
mavenLocal()
maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
mavenCentral()
}
}
allprojects {
group = 'com.xingyu'
version = '0.0.1-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
repositories {
mavenLocal()
maven {url 'https://maven.aliyun.com/repository/public'}
mavenCentral()
}
dependencies {
// 提供注解处理器
annotationProcessor 'org.projectlombok:lombok:1.18.24'
implementation 'org.projectlombok:lombok:1.18.24'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
testImplementation 'org.projectlombok:lombok:1.18.24'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
implementation 'org.springframework:spring-context:6.0.3'
implementation 'org.springframework:spring-jdbc:6.0.3'
runtimeOnly 'mysql:mysql-connector-java:8.0.31'
implementation 'org.mybatis:mybatis:3.5.11'
implementation 'com.alibaba:druid:1.2.15'
}
test {
useJUnitPlatform()
}
}
2.1.2 spring.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/beans/spring-context.xsd">
<bean id="dataSource" class="com.xingyu.pojo.JdbcConfig">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1"/>
<property name="userName" value="root"/>
<property name="passWord" value="root"/>
</bean>
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
</bean>
</beans>
@Data
public class JdbcConfig {
private String driverClassName;
private String url;
private String userName;
private String passWord;
}
public interface UserDao {
}
public class UserDaoImpl implements UserDao {
}
public interface UserService {
}
public class UserServiceImpl implements UserService {
public void setUserDao(UserDao userDao) {
System.out.println("beanfactory去调用该方法获得userDao设置到此处:" + userDao);
}
}
2.1.3 BeanFactory入门
public class Application {
public static void main(String[] args) {
// 创建工厂对象
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建一个读取器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// 读取器绑定工厂
reader.loadBeanDefinitions("spring.xml");
// 根据id获取实例对象
JdbcConfig dataSource = (JdbcConfig) beanFactory.getBean("dataSource");
System.out.println(dataSource);
UserService userService = (UserService) beanFactory.getBean("userService");
System.out.println(userService);
UserDao userDao = (UserDao) beanFactory.getBean("userDao");
System.out.println(userDao);
}
}
2.1.4 ApplicationContext入门
public class Application {
public static void main(String[] args) {
// 创建工厂对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 根据id获取实例对象
JdbcConfig dataSource = (JdbcConfig) applicationContext.getBean("dataSource");
System.out.println(dataSource);
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
System.out.println(userDao);
}
}
2.1.5 ApplicationContext和BeanFactory的关系
2.2 IOC的XML配置
- bean
作用:定义spring中的资源,受此标签定义的资源将受到spring控制
- bean属性scope
定义bean的作用范围
取值:
- singleton:设定创建出的对象保存在spring容器中,是一个单例的对象
- prototype:设定创建出的对象保存在spring容器中,是一个非单例的对象
- request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置
- bean生命周期
定义bean对象在初始化或销毁时完成的工作
<bean init-method=“init” destroy-method="destroy>
- bean对象创建方式
- factory-bean
定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作- factory-bean,factory-method
定义bean对象创建方式,使用实例工厂的形式创建bean,兼容早期遗留系统的升级工作
2.2.1 Springbean的配置
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/beans/spring-context.xsd">
<bean id="dataSource" class="com.xingyu.pojo.JdbcConfig">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1"/>
<property name="userName" value="root"/>
<property name="passWord" value="root"/>
</bean>
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
</bean>
</beans>
2.2.1.1 beanName
不配置id的话,bean的名称默认为类的全限定名
2.2.1.2 别名 name属性
<bean id="userDao" name="userDao2" class="com.xingyu.dao.impl.UserDaoImpl">
</bean>
2.2.1.3 作用域
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl" scope="singleton">
<property name="userDao" ref="userDao"/>
</bean>
2.2.1.4 延迟加载
<bean id="userDao" name="userDao2" class="com.xingyu.dao.impl.UserDaoImpl" lazy-init="true">
</bean>
2.2.1.5 初始化
public class UserServiceImpl implements UserService {
public void init(){
System.out.println("初始化方法");
}
public void destroy(){
System.out.println("销毁方法");
}
public void setUserDao(UserDao userDao) {
System.out.println("beanfactory去调用该方法获得userDao设置到此处:" + userDao);
}
}
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy">
<property name="userDao" ref="userDao"/>
</bean>
2.2.1.6 InitializingBean
属性设置之后,beand的init方法之前
public class UserServiceImpl implements UserService, InitializingBean {
public void init(){
System.out.println("初始化方法");
}
public void destroy(){
System.out.println("销毁方法");
}
public void setUserDao(UserDao userDao) {
System.out.println("beanfactory去调用该方法获得userDao设置到此处:" + userDao);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
}
2.2.2 Bean的实例化配置
a、构造方法实例化(无参、有参)
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
</bean>
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" name="userDao2" class="com.xingyu.dao.impl.UserDaoImpl">
</bean>
b、工厂方法实例化(静态工厂、实例工厂)
public class MyFactoryBean {
public static UserDao userDao(){
return new UserDaoImpl();
}
}
<bean id="userDao1" class="com.xingyu.pojo.MyFactoryBean" factory-method="userDao">
</bean>
public class MyFactoryBean {
public UserDao userDao(){
return new UserDaoImpl();
}
}
<bean id="myFactoryBean" class="com.xingyu.pojo.MyFactoryBean">
</bean>
<bean id="userDao1" factory-bean="myFactoryBean" factory-method="userDao"/>
c、实现FactoryBean
public class MyFactoryBean implements FactoryBean<UserDao> {
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
}
<bean id="userDao1" class="com.xingyu.pojo.MyFactoryBean">
</bean>
2.2.3 依赖注入
a、构造器注入
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
</bean>
b、 set注入
<bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
</bean>
<bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
</bean>
<bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
<property name="map">
<map>
<entry key="1" value="123"/>
<entry key="2" value="345"/>
</map>
</property>
</bean>
<bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
<property name="properties">
<props>
<prop key="1">123</prop>
<prop key="2">345</prop>
</props>
</property>
</bean>
c、自动装配
d、命名空间
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="com.xingyu.pojo.JdbcConfig" p:url="jdbc:mysql://localhost:3306/db1">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="userName" value="root"/>
<property name="passWord" value="root"/>
</bean>
</beans>
2.2.4 Bean实例化的基本流程
2.2.5 Spring的后处理器
- BeanFactoryPostProcessor
public class MyFactoryProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyFactoryProcessor 执行了");
}
}
<bean id="myFactoryProcessor" class="com.xingyu.processor.MyFactoryProcessor"></bean>
- BeanPostProcessor
public class MyBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization 执行了");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization 执行了");
return bean;
}
}
<bean id="myBeanProcessor" class="com.xingyu.processor.MyBeanProcessor"></bean>
2.2.6 Spring Bean的生命周期
a、bean的初始化
- 属性注入
beanDefinition中封装有Bean实体的注入信息通过propertyValues进行存储
- 循环依赖
多个实体之间相互引用并形成闭环的情况叫做循环依赖
- 三级缓存
解决循环依赖问题
2.3 注解开发
2.3.1 bean
@Component,@Repository,@Service,@Controller :创建bean
@Scope 作用域
@Lazy 懒加载
@Value 值注入
@Autowired 引用类型注入
@Configuration // 声明为配置类,替代spring.xml
@ComponentScan("com.xingyu") // 扫包
@Import(JdbcConfig.class) //导入配置类或者bean
public class MyConfig {
@Bean
public DruidDataSource dataSource(@Autowired JdbcConfig jdbcConfig){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcConfig.getDriverClassName());
dataSource.setUrl(jdbcConfig.getUrl());
dataSource.setUsername(jdbcConfig.getUserName());
dataSource.setPassword(jdbcConfig.getPassWord());
return dataSource;
}
}
2.3.2 属性注入
a. @Value
@PropertySource("classpath:application.properties") // 导入properties文件
@Data
public class JdbcConfig {
// 值注入
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.userName}")
private String userName;
@Value("${jdbc.passWord}")
private String passWord;
@Autowired // 引用类型注入
private UserService userService;
}
b. @Autowired和@Resource
@Autowired // 根据类型注入,如果没有第二次根据name找,如果还没有则报错
@Resource // 不指定名称则根据type找,指定则根据name找,没找到就报错
c. 配置类替代spring.xml
@Configuration // 声明为配置类,替代spring.xml
@ComponentScan("com.xingyu") // 扫包
@Import(JdbcConfig.class) //导入配置类或者bean
public class MyConfig {
@Bean
public DruidDataSource dataSource(@Autowired JdbcConfig jdbcConfig){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcConfig.getDriverClassName());
dataSource.setUrl(jdbcConfig.getUrl());
dataSource.setUsername(jdbcConfig.getUserName());
dataSource.setPassword(jdbcConfig.getPassWord());
return dataSource;
}
}
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
2.3.3.4 Import,ImportSelector,ImportBeanDefinitionRegistrar整合第三方框架
@Configuration // 声明为配置类,替代spring.xml
@ComponentScan("com.xingyu") // 扫包
@Import({JdbcConfig.class,JdbcConfigSelector.class,JdbcConfigBeanDefinitionRegistrar.class}) //导入配置类或者bean
public class MyConfig {
@Bean
public DruidDataSource dataSource(@Autowired JdbcConfig jdbcConfig){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcConfig.getDriverClassName());
dataSource.setUrl(jdbcConfig.getUrl());
dataSource.setUsername(jdbcConfig.getUserName());
dataSource.setPassword(jdbcConfig.getPassWord());
return dataSource;
}
}
public class JdbcConfigSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{JdbcConfig.class.getName()};
}
}
public class JdbcConfigBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName(JdbcConfig.class.getName());
registry.registerBeanDefinition("jdbcConfig",beanDefinition);
ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
}
}
3、 AOP
3.1 简介
AOP,面向切面编程,是面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与方法、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。
3.1.1 相关概念
3.1.2 动态代理技术
@Service
public class UserServiceImpl implements UserService, InitializingBean {
@Autowired
private UserDao userDao;
@PostConstruct
public void init(){
System.out.println("初始化方法");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
@Override
public void show() {
System.out.println("UserServiceImpl show");
}
}
@Component
public class MyAdvice {
public void before(){
System.out.println("MyAdvice before");
}
public void after(){
System.out.println("MyAdvice after");
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
String aPackage = bean.getClass().getPackage().getName();
if(aPackage.equals("com.xingyu.service.impl")){
Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MyAdvice myAdvice = applicationContext.getBean(MyAdvice.class);
myAdvice.before();
Object result = method.invoke(bean, args);
myAdvice.after();
return result;
}
});
return beanProxy;
}
return bean;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.applicationContext = context;
}
}
3.1.3 cglb动态代理技术
3.2 xml开发
3.2.1 入门
- 依赖
runtimeOnly 'org.aspectj:aspectjweaver:1.9.19'
- 代码
public class MyAdvice {
public void before(){
System.out.println("MyAdvice before");
}
public void after(){
System.out.println("MyAdvice after");
}
}
- 配置
<?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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/beans/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置目标类-->
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
</bean>
<!--配置切面类-->
<bean id="myAdvice" class="com.xingyu.advices.MyAdvice"/>
<!--aop配置-->
<aop:config expose-proxy="true">
<aop:pointcut id="pointcut" expression="execution(public * *.*(..))"/>
<aop:aspect id="myAdvice" ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
3.2.2 切点表达式
【权限修饰符】 返回值 包名.类型.方法名(参数)
<aop:config expose-proxy="true">
<aop:pointcut id="pointcut" expression="execution(public * *.*(..))"/>
<aop:aspect id="myAdvice" ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
3.2.3 五种通知类型
<?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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/beans/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置目标类-->
<bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
</bean>
<!--配置切面类-->
<bean id="myAdvice" class="com.xingyu.advices.MyAdvice"/>
<!--aop配置-->
<aop:config expose-proxy="true">
<aop:pointcut id="pointcut" expression="execution(public * *.*(..))"/>
<aop:aspect id="myAdvice" ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
3.3 注解开发
@EnableAspectJAutoProxy
@Component
public class MyAdvice {
@Pointcut(value = "execution(public * com.xingyu.controller.*(..))")
public void pointcut(){
}
@Before(value = "pointcut()")
public void before(){
System.out.println("MyAdvice before");
}
@After(value = "pointcut()")
public void after(){
System.out.println("MyAdvice after");
}
@Around(value = "pointcut()")
public void around(){
System.out.println("MyAdvice around");
}
@AfterReturning(value = "pointcut()")
public void afterReturning(){
System.out.println("MyAdvice afterReturning");
}
@AfterThrowing(value = "pointcut()")
public void afterThrowing(){
System.out.println("MyAdvice afterThrowing");
}
}