Spring
一、简介
- Spring轻量级,开源javaEE框架
- 简化开发
- 两大核心部分:IOC,AOP
- IOC:控制反转:把创建对象的过程交给Spring进行管理
(1)IOC底层原理
(2)IOC接口(BeanFactory)
(3)IOC操作Bean管理(基于xml)
(4)IOC操作Bean管理(基于注解) - AOP:面向切面编程:在不修改源代码的情况下,进行功能增加或增强
- IOC:控制反转:把创建对象的过程交给Spring进行管理
- 特点:
- 方便解耦,简化开发
- Aop
- 方便程序测试
- 方便集成其他框架
- 降低API使用难度
- 方便事务操作
二、IOC
1.什么是IOC
(1)控制反转,把对象的创建和对象之间的调用过程交给Spring进行管理
(2)使用IOC的目的,是为了降低耦合
2.IOC底层原理
(1)xml解析、工厂模式、反射
工厂模式:[https://www.runoob.com/design-pattern/factory-pattern.html](https://www.runoob.com/design-pattern/factory-pattern.html)xml解析:反射:<br />
3.IOC接口(接口)
(1)IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
(2)Spring提供IOC容器实现的两种方式(两个接口):
BeanFactory:是IOC容器基本实现,内部使用接口,一般不提供开发人员使用
*加载配置文件时不会创建对象,在获取对象时才创建。
ApplicationContext:BeanFactory接口的子接口,提供更多更强大功能,由开发人员使用
*加载配置文件时就会创建对象
(3)ApplicationContext实现类
4.IOC操作Bean管理
- 什么是Bean管理
Spring创建对象
Spring注入属性
- Bean管理操作的两种方式
基于xml文件
基于注解
- 基于XML方式
- 基于XML方式创建对象
<bean id="user" class="com.study.spring5.User"></bean>
在spring配置文件中使用bean标签
bean标签属性:
id:唯一标识
class:创建的类的全路径(包+类)
name:早期属性,相当于id,用于struts1
- 创建对象时默认执行无参构造方法,**所以必须有无参构造方法**
2. 基于XML方式注入属性
- DI:依赖注入,就是注入属性
第一种方式:set方法
- 创建类,属性及其set方法
- 在spring配置文件中配置对象的创建,配置属性注入
<bean id="book" class="com.atguigu.spring5.Book">
<property name="bname" value="大耳朵图图"></property>
<property name="author" value="胡英俊"></property>
</bean>
第二种方式:构造方法
- 创建类,以及有属性的参数构造方法
<bean id="orders" class="com.atguigu.spring5.Orders">
<constructor-arg name="oname" value="胡图图"></constructor-arg>
<constructor-arg name="address" value="幸福社区幸福街幸福花园1201号"></constructor-arg>
</bean>
5.p名称空间注入(了解)
简化set方法注入
- 添加p名称空间在配置文件中

- 属性注入
6.XML方式注入其他类型属性
(1)字面量
null值
<property name="address"> <null></null> </property>属性值包含特殊符号

(2)外部bean
xml 注入对象
- 创建service,Dao类
- 在service调用Dao里的方法
- 在spring配置文件中进行配置 ```java public class UserService {
// 创建UserDao类属性,生成set方法
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("service add");
// 原始调用方式 // UserDao userDao = new UserDaoImpl(); // userDao.update();
// spring方式
userDao.update();
}
}
```java
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("dao update");
}
}
<bean id="userService" class="com.atguigu.spring5.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
xml 注入集合属性
- 注入数组
- 注入List集合
注入Map集合 ```java public class Stu { private String[] courses; private List
list; private Map maps; private Set set; public void setSet(Set
set) { this.set = set; } public String[] getCourses() { return courses; }
public void setCourses(String[] courses) { this.courses = courses; }
public void setList(List
list) { this.list = list; } public void setMaps(Map
maps) { this.maps = maps; } public void test(){ System.out.println(Arrays.toString(courses)); System.out.println(list); System.out.println(maps); System.out.println(set); } }
```java
<bean id="student" class="com.atguigu.spring5.collectiontype.Stu">
<!-- 数组 -->
<property name="courses">
<array>
<value>Java</value>
<value>C++</value>
<value>C#</value>
</array>
</property>
<!-- List -->
<property name="list">
<list>
<value>Jack</value>
<value>Rose</value>
</list>
</property>
<!-- Maps -->
<property name="maps">
<map>
<entry key="Jack" value="Java"></entry>
<entry key="Rose" value="C++"></entry>
</map>
</property>
<!-- Set -->
<property name="set">
<set>
<value>MySQL</value>
<value>Oracle</value>
</set>
</property>
</bean>
在集合中设置对象
<property name="coursesList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property>集合注入提取成公共部分
(1)在配置文件中引入名称空间util
(2)
<util:list id="bookList">
<value>《哈皮父子》</value>
<value>《大耳朵图图》</value>
<value>《猫和老鼠》</value>
</util:list>
<bean id="book" class="com.atguigu.spring5.collectiontype.Book">
<property name="list" ref="bookList"></property>
</bean>
7.IOC操作Bean管理(FactoryBean)
- Spring有两种类型bean,一种普通bean,一种工厂bean(FactoryBean)
普通bean:配置文件中定义的类型即为返回类型
工厂bean:在配置文件中定义的类型可以与返回类型不一致
(1)创建一个类,作为工厂bean,实现FactoryBean接口
(2)实现接口方法,定义返回的bean类型
public class MyBean implements FactoryBean {
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("C");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
@Test
public void test3() {
ApplicationContext context =new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
</bean>
8.bean的作用域
- Spring中可以设置创建bean是单实例还是多实例,默认单实例对象
测试:
结果:
- 设置Spring多实例对象
在Spring配置文件bean标签中有属性scope用于设置
scope:默认singleton单例
prototype多实例

request:
session:
- singleton与prototype区别
第一:singleton单实例,prototype多实例
第二:设置singleton,当加载spring配置文件时就会创建单实例对象。
设置prototype,是在调用getBean方法时创建多实例对象
9.bean的生命周期
(1)从对象创建到对象销毁的过程
(2)生命周期
- 通过构造器创建bean实例
- 为bean的属性设置值和对其他bean引用(调用set方法)
- 调用bean初始化的方法(需要进行配置)
- bean可以使用了
-
10.xml自动装配
(1)什么是自动装配
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
(2)示例
标签autowire:byName:根据名称注入,bean中id需要与类中属性名称一致
byType:根据类型注入
11.引入外部属性文件
(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/test"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean>(2)通过引入外部文件配置数据库连接池
创建外部属性文件,存放数据库连接池信息

- 外部properties配置文件引入到Spring配置文件中
引入context名称空间
在配置文件中使用标签引入配置文件
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
12.基于注解方式
(1)什么是注解
特殊标记:@注解名称(属性=值,属性=值…)
使用注解:类,方法,属性
目的:简化xml配置
(2)Spring针对Bean管理创建对象提供的注解:4个
- @Component:普通组件
- @Service:一般用于业务逻辑
- @Controller:一般用于控制层
- @Repository:一般用于持久化
四个注解功能是一致的,都可以用来创建bean实例
(3)代码实现
- 引入aop依赖
开启组件扫描
<!-- 开启组件扫描 扫描多个组件: 1.多个包使用逗号隔开 2.扫描包的上层目录 --> <context:component-scan base-package="com.atguigu.spring5"></context:component-scan>创建类,添加注解
@Service(value = "userService") public class UserService { public void add(){ System.out.println("User service add..."); } }(4).开启组件扫描细节注意:
- 可以配置哪些扫描,哪些不扫描
(5)属性注入<context:component-scan base-package="com.atguigu.spring5" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
(6)纯注解开发(1)@Autowired 根据属性类型进行自动装配 1.service与dao类上都添加创建对象注解 2.在Service中注入dao对象:在service类添加dao类型属性,添加注解 (2)@Qualifier 根据名称进行注入 @Qualifier注解要与@Autowired一起使用 (3)@Resource 可根据类型也可根据名称进行注入 @Resource(name = "userDao") private UserDao userDao; (4)@Value 注入普通类型属性 @Value(value = "ABC") private String userName;
- 创建配置类,代替配置文件 ```java @Configuration @ComponentScan(basePackages = {“com.atguigu.spring5”}) public class SpringConfig {
}
2. 使用(获取bean)
`ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);`
```java
@Test
public void testUserService2() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",UserService.class);
userService.add();
}
三、AOP
1.什么是AOP
面向切面编程。对业务逻辑各个部分进行隔离,降低耦合度,提升可重用性
在不修改原有源代码的方式,在主干功能中添加新功能。
2.AOP底层原理
- 动态代理
(1)两种情况:
有接口:JDK动态代理
创建UserDao接口实现类代理对象,增强类的方法。
无接口:CGLIB动态代理
创建当前子类的代理对象,增强类的方法。
3.AOP(JDK动态代理)
- 使用Proxy类里面的方法创建代理对象

- 三个参数:
类加载器
增强方法所在类实现的接口
实现接口InvocationHandler,创建代理对象,写增强方法
代码实现:
- 创建接口类,定义方法
- 创建实现类,实现方法
- 使用Proxy类创建接口代理对象 ```java /**
- @author Created by MrNnobody
- @date 2021/9/8 9:55
Welcome to browse and correct */ public class JdkProxy {
public static void main(String[] args) { Class[] interfaces = {UserDao.class}; // 使用匿名内部类方式 // Proxy.newProxyInstance(UserDao.class.getClassLoader(), interfaces, new InvocationHandler() { // @Override // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // return null; // } // }); // 使用实现InvocationHandler方式创建 UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1,2); System.out.println(“result” + result); }
}
class UserDaoProxy implements InvocationHandler{
// 1.代理的是谁的对象,就该该对象传过来
//有参构造传递
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
//增强方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行前
System.out.println("前" + method.getName() + "传递的参数" + Arrays.toString(args));
//执行
Object res = method.invoke(obj,args);
//执行后
System.out.println("后" + obj);
return res;
}
}
4. AOP(术语)
1. 连接点
类中可以被增强的方法,称为连接点。
2. 切入点
类中被真正增强的方法。
3. 通知(增强)
实际增强的逻辑部分<br />通知有多种类型:<br />前置<br />后置<br />环绕<br />异常<br />最终 finally
4. 切面(过程)
把通知应用到切入点,就叫做切面
5. AOP(准备)
(1)AspectJ<br />独立框架<br />(2)基于AspectJ实现AOP
1. 基于xml配置
2. 基于注解
(3)在项目中引入AOP相关依赖<br />(4)切入点表达式<br />语法:<br />execution([权限修饰符] [返回类型] [类全路径] [方法名] ([参数列表]))<br />举例:<br />1.对com.atschool.dao.BookDao 内的add进行增强<br />execution(* com.atschool.dao.BookDao.add(..))<br />2.对com.atschool.dao.BookDao 内的所有方法进行增强<br />execution(* com.atschool.dao.BookDao.*(..))
6. 基于注解AspectJ
(1)创建类,实现方法,对其增强
```java
public class User {
public void add(){
System.out.println("add");
}
}
(2)创建增强类,编写增强逻辑
在增强类中创建方法,不同方法代表不同增强类型
(3)进通知配置
- 配置文件中开启注解扫描

- 用注解创建User和UserProxy对象
@Component
public class User {
- 在增强类上添加@Aspect注解
@Component
@Aspect
public class UserProxy {
- 在spring配置中开启或生成代理对象
- 配置不同类型的通知
在增强类里,在作为通知的方法上添加通知类型注解,使用切入点表达式配置
@Component
@Aspect
public class UserProxy {
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("before");
}
}
