一、spring
1 2 3 4 5 6 7 8 9
| spring核心学习内容 IOC,AOP,jdbcTemplate,声明式事务 Maven构建,不用闸包!!!! 1.IOC:控制反转,可以管理Java对象 2.AOP:切面编程 3.JDBCTemplate:是spring提供一套访问数据库技术 4.声明式事务:基于ioc/aop实现事务管理
几个重要概念: Spring可以整合其他框架(Spring是管理框架的框架) 两个核心概念:IOC、AOP
|
二、快速入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 1.构建Maven模块 2.引入依赖: pendency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>7.0.5</version> </dependency>
3.在resources文件夹下创建xml文件(spring的) 4.配置xml文件: <!--配置User对象--> <!-- 这里解读: 1.在beans文件中可以配置多个bean 2.bean表示一个Java对象!!!! 3.class属性是用于指定类的全路径->spring底层使用反射创建 4.id属性表示该Java对象在spring容器中的id,通过id获取到对象,如果没有配置id,按照全类名配置!! 5.property 表示设置属性,name表示该类里面的变量,value表示设置值 --> <bean class="om.itchen.Spring6.User" id="user1"> <!--1.当我们给某个Bean对象设置属性的时候--> <!--2.底层使用对应的setter方法完成的,比如setName()--> <!--3.如果没有该方法,就会报错!!!!!--> <property name="id" value="100"/> <property name="name" value="牛魔王"/> <property name="skill" value="芭蕉扇"/> </bean>
|
三、获取bean
1 2 3 4 5 6 7 8 9 10
| ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = (User) context.getBean("user1"); System.out.println("id获取Bean:" + user);
User user2 = context.getBean(User.class,"user1"); System.out.println("根据类型获取:" + user2);
|
四、设置bean属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 1. setter方法注入: <bean id="book1" class="com.itchen.spring6.iocxml.di.Book"> 一定要有setter方法,否则无法注入!!! <property name="bname" value="java" /> <property name="author" value="Xc" /> </bean>
2.构造器注入: <bean id="book2" class="com.itchen.spring6.iocxml.di.Book"> <!--构造器注入--> <constructor-arg value="python" index="0" /> <constructor-arg value="老陈" index="1" /> </bean>
3.ref标签(外部引入) <bean class="spring.dao.MemberDAOImpl" id="memberDAO"/> 第一个bean <bean class="spring.service.MemberServiceImpl" id="memberService"> 引入第一bean <property name="memberDAO" ref="memberDAO" /> ref="id名" </bean>
注:特殊值:< 是 <; > 是 >; 使用 <![CDATA[a < b]]> CDATA节; <null /> 空值;
|
五、特殊属性注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| 1.级联对象注入(ref标签): <bean id="dept1" class="com.itchen.spring6.iocxml.di.Dept"> <!--建立父级(部门) --> <property name="dname" value="开发部" /> </bean> <bean id="emp1" class="com.itchen.spring6.iocxml.di.Emp"> <!-- 建立子级(员工) --> <property name="ename" value="小陈" /> <property name="age" value="20" /> <!--对象属性注入--> <property name="dept" ref="dept1" /> <!--修改父级的值--> 这里父类和子类都要有get方法!!! <property name="dept.dname" value="测试部" /> </bean>
2.数组类型注入: <bean id="emp1" class="com.itchen.spring6.iocxml.di.Emp"> <!--数组类型注入--> <property name="hobby"> <array> 使用array数组标签 <value>打篮球</value> 可以有多个值 <value>跳舞</value> <value>唱歌</value> </array> </property> </bean>
3.List类型注入: <bean id="dept3" class="com.itchen.spring6.iocxml.di.Dept"> <property name="dname" value="开发部" /> <property name="emplist"> <list> 使用list数组标签 <ref bean="emp2" /> <ref bean="emp3" /> </list> </property> </bean>
4.Map类型注入: <!--创建老师--> <bean id="teacher1" class="com.itchen.spring6.iocxml.dimap.Teacher"> <property name="tname" value="王老师" /> <property name="tid" value="1" /> </bean> <!--创建学生--> <bean id="student1" class="com.itchen.spring6.iocxml.dimap.Student"> <property name="sid" value="1" /> <property name="sname" value="小陈" /> <!--map属性类型注入--> <property name="teacherMap"> <map> map标签,entry标签,key标签(存放键),ref标签(存放值) <entry> <key> <value>1</value> </key> <ref bean="teacher1" /> </entry> </map> </property> </bean>
5.Set和properties属性类型注入: 这里简短些 Set: 和list一样 <set> </set> properties: <props> <prop key="username">itchen</prop> </props>
6.数据重用: <bean parent="monster1" id="m" class="....."> 如果想重用其他bean,使用parent属性!!!
|
六、util配置和p标签
1 2 3 4 5 6 7 8 9 10 11 12
| 1.如果有重复使用的值,有不想创建类,可以使用util配置 注:支持list map set properties <util:list id="myBookList"> <value>三国演义</value> <value>红楼梦</value> </util:list> //使用用ref即可
2.普通代码太长,可以使用p标签缩短 写在bean属性上 <bean id="book4" class="com.itchen.spring6.iocxml.di.Book" p:bname="水浒传" p:author="施耐庵" />
|
七、bean的作用域和生命周期
1.bean的作用域
作用域定义了 Spring 容器创建 Bean 实例的规则,Spring 7 中核心作用域有 6 种,其中单例(singleton) 和原型(prototype) 是最常用的基础作用域,其余为 Web 环境专属。
核心作用域详解(按使用频率排序)
| 作用域 |
核心含义 |
适用场景 |
Spring 7 注意点 |
| singleton |
容器中仅创建 1 个实例,全局共享(默认作用域) |
无状态的工具类、服务类(如 Service) |
优化了单例 Bean 的初始化性能 |
| prototype |
每次获取 Bean 时创建新实例,容器仅负责创建,不管理销毁 |
有状态的对象(如 User、Order) |
适配 Java 17 密封类,创建效率提升 |
| request |
Web 环境中,每个 HTTP 请求创建 1 个实例 |
Web 请求级别的数据载体 |
需结合 Spring MVC 7.0+ |
| session |
Web 环境中,每个 HTTP Session 创建 1 个实例 |
用户会话级别的数据(如购物车) |
兼容 Servlet 6.0+ |
| application |
Web 环境中,整个 Web 应用仅 1 个实例(区别于 singleton:基于 ServletContext) |
应用级全局配置 |
与 singleton 功能重叠,极少使用 |
| websocket |
WebSocket 连接周期内仅 1 个实例 |
实时通信场景 |
适配 WebSocket 1.1 规范 |
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?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 https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="singletonService" class="com.example.SingletonService" scope="singleton"/>
<bean id="prototypeUser" class="com.example.User" scope="prototype"/>
</beans>
|
2.bean的生命周期
(1)实例化(Instantiation)
容器根据配置(XML / 注解)创建 Bean 实例(底层通过反射 new 对象),此时仅分配内存,未注入任何属性。
(2)属性注入(Populate)
容器将依赖的 Bean / 值注入到当前 Bean 的属性中(如 XML 中的 <property>/<constructor-arg>)。
(3)初始化(Initialization)
Bean 实例就绪前的自定义操作,有 2 种常用扩展方式:
- 实现
InitializingBean 接口(重写 afterPropertiesSet());
- XML 中配置
init-method(自定义初始化方法)。
(4)使用(Usage)
Bean 完全就绪,可通过容器获取并调用方法。
(5)销毁(Destruction)
容器关闭时执行的清理操作,有 2 种扩展方式:
- 实现
DisposableBean 接口(重写 destroy());
- XML 中配置
destroy-method(自定义销毁方法)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| public class beanLife implements InitializingBean, DisposableBean { private String name;
public void setName(String name) { this.name = name; System.out.println("2. 注入属性:name = " + name); }
public beanLife() { System.out.println("1. 实例化 Bean(调用构造器)"); }
@Override public void afterPropertiesSet() throws Exception { System.out.println("3. 执行 InitializingBean.afterPropertiesSet()"); }
public void myInit() { System.out.println("4. 执行自定义 init-method:myInit()"); }
@Override public void destroy() throws Exception { System.out.println("6. 执行 DisposableBean.destroy()"); }
public void myDestroy() { System.out.println("7. 执行自定义 destroy-method:myDestroy()"); }
public void queryUser() { System.out.println("5. 使用 Bean:查询用户,name = " + name); } }
<?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="beanLife" class="com.itchen.spring6.iocxml.beanLife.beanLife" init-method="myInit" destroy-method="destroy"> <property name="name" value="张三" /> </bean> </beans>
public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext life = new ClassPathXmlApplicationContext("beanLife.xml"); beanLife beanLife = life.getBean("beanLife", beanLife.class); beanLife.queryUser(); life.close(); } }
1. 实例化 Bean(调用构造器) 2. 注入属性:name = 张三 3. 执行 InitializingBean.afterPropertiesSet() 4. 执行自定义 init-method:myInit() 5. 使用 Bean:查询用户,name = 张三 6. 执行 DisposableBean.destroy()
|
八、自动装配
1
| <bean id="userService" class="com.itchen.spring6.iocxml.auto.service.userServiceImp.UserServiceImp" autowire="byType"> 使用autowire自动装配
|
| 模式 |
含义 |
优点 |
缺点 |
| no |
关闭自动装配(默认),需手动配置依赖注入 |
可控性高 |
配置繁琐 |
| byName |
按「属性名」匹配容器中的 Bean ID,匹配成功则注入 |
简单,匹配规则明确 |
需保证属性名和 Bean ID 完全一致 |
| byType |
按「属性类型」匹配容器中的 Bean,匹配成功则注入(Spring 7 推荐) |
无需关注 Bean ID,更灵活 |
同类型多个 Bean 时会报错 |
| constructor |
按构造器参数的「类型」匹配 Bean,注入到构造器中 |
适合不可变 Bean(final) |
同类型多个 Bean 时会报错 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package com.example; public class UserDao { public void query() { System.out.println("UserDao 执行查询"); } }
package com.example; public class UserService { private UserDao userDao;
public void setUserDao(UserDao userDao) { this.userDao = userDao; }
public UserService(UserDao userDao) { this.userDao = userDao; }
public UserService() {}
public void doService() { userDao.query(); } }
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1. 定义被依赖的 Bean:UserDao(ID 为 userDao) --> <bean id="userDao" class="com.example.UserDao"/>
<!-- 2. 定义目标 Bean:UserService,开启自动装配 --> <!-- 方式 1:按名称装配(byName):匹配属性名 userDao → Bean ID userDao --> <bean id="userService" class="com.example.UserService" autowire="byName"/>
<!-- 方式 2:按类型装配(byType):匹配属性类型 UserDao → 容器中唯一的 UserDao Bean --> <!-- <bean id="userService" class="com.example.UserService" autowire="byType"/> -->
<!-- 方式 3:按构造器装配(constructor):匹配构造器参数类型 UserDao --> <!-- <bean id="userService" class="com.example.UserService" autowire="constructor"/> -->
</beans>
|
九、基于注解开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 注解可以放到类、方法、字段上,简化开发; 流程: 1.创建xml文件 2.输入: xmlns:context="http://www.springframework.org/schema/context" 1 使用context空间 xsi:schemaLocation=" http://www.springframework.org/schema/context 2 http://www.springframework.org/schema/context/spring-context.xsd 3
开启组件扫描: <context:component-scan base-package="com.itchen" />
3.使用注解 @Component(value = "user") //等同于 <bean id="user" class="...."> 不写默认类名!!! public class User{
}
注解类型: @Component 表示一个容器中的组件,其作用在任何一个层次内,如@Service; @Repository 表示Dao层,与@Component作用相同 @Service 表示业务层,与@Component作用相同 @Controller 表示控制层,与@Component作用相同 @Autowired 自动装配,可以用到属性、set方法、构造方法、形参(set方法不可以) 默认byType类型 @Qualifier("bean类名") 与@Autowired 联合使用,当有两个相同的类注入时,使用该注解 byName类型 @Resource 自动装配,可以自动切换byName和byType类型! 需要引入依赖(@Resource是jdk自带的): <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>2.1.1</version> </dependency> 注:如果类只有一个有参构造函数,可以省略@Autowired!!!!!
|
十、全注解开发
如何省略xml文件??使用注解
1 2 3 4 5 6 7 8 9 10
|
@Configuration 配置类注解,代替xml文件 @ComponentScan("包路径") 与@Configuration联合使用,进行包扫描 @bean 表示注入bean,交给容器管理
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
|
十一、AOP切面编程
1.快速入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 1.引入依赖: <!--引入 spring aop依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>7.0.5</version> </dependency> <!--引入 spring aspects依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>7.0.5</version> </dependency>
2.创建一个接口类和实现类
3.xml配置 <!--开启组件扫描--> <context:component-scan base-package="com.itchen.Spring6.annoaop" /> <!--开启aspect自动代理,为目标对象生成代理--> <aop:aspectj-autoproxy />
4.创建切面类 @Aspect //切面类 @Component public class LogAspect { //前置通知 @Before(value = "execution(public int com.itchen.Spring6.annoaop.CalculatorImpl.* (..))") public void beforeMethod(){ System.out.println("前置通知"); } }
5.创建bean容器进行测试即可
|
2.通知方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 1.前置通知:@Before 在方法调用前 使用:@Before(value = "execution(访问修饰符 增强方法返回值类型 方法全类名.方法名(*所有方法) 形参(..任意类型))")
2.返回通知:@AfterReturning 在方法调用之后 他和后置通知的区别是可以获取方法返回值 @AfterReturning(value = "execution(访问修饰符 增强方法返回值类型 方法全类名.方法名 形参",returning = "aa")类型Object
3.异常通知:@AfterThrowing 方法抛出异常通知 @AfterThrowing(value = "execution(访问修饰符 增强方法返回值类型 方法全类名.方法名 形参)",throwing = "ex")类型Object
4.后置通知:@After 有没有发生异常都会通知,又称最终通知 @After(value = "execution(访问修饰符 增强方法返回值类型 方法全类名.方法名(*所有方法) 形参(..任意类型))")
5.环绕通知:@Around 上面四个的总和,使用try..catch...finally使用上面四个通知!!!!!! @Around(value = "execution(访问修饰符 增强方法返回值类型 方法全类名.方法名(*所有方法) 形参(..任意类型))")
|