SSM笔记之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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
该id属性是标识单个 bean 定义的字符串。
该class属性定义 bean 的类型并使用完全限定的类名。
-->
<bean id="..." class="">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
1. IOC(控制反转)
IOC:由spring容器去控制对象的创建
DI:自身对象中的内置对象是通过注入的方式进行创建
1.1 依赖注入(DI)
实例化容器
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
1. 构造器注入:
<!--第一种方式,下标赋值! -->
<bean id="user" class="com.xawl.pojo.User">
<constructor-arg index="0" value="狂神说JAVA"/>
</bean>
<!--第二种方式:通过类创建,不建议使用-->
<bean id="user" class="com.xawl.pojo.User">
<constructor-arg type="java.lang.String" value="qinjiang"/>
</bean>
<!--第三种方式,直接通过参数名来设置-->
<!--id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的全限定名, 包名+类型
name:也是别名,而且name可以同时取多个别名-->
<bean id="user" class="com.xawl.pojo.User">
<constructor-arg name="name" value="秦疆"/>
</bean>
2. 属性注入(set注入)
<!-- 使用Spring来创建对象,在Spring这些都称为Bean -->
<bean id="hello" class="com.xawl.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
<bean id="student" class="com.xawl.pojo.Student">
<!--第一种,普通值注入,value-->
<property name="name" value="秦晋"/>
<!--第二种,Bean注入,ref-->
<property name="address" ref="address"/>
<!--数组注入,ref-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
<!--list-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>敲代码</value>
<value>看电影</value>
</list>
</property>
<!--map-->
<property name="card">
<map>
<entry key="身份证" value="12321321312 "/>
<entry key="银行卡" value="2131543546 "/>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--properties-->
<property name="info">
<props>
<prop key="driver">201293123</prop>
<prop key="url">sadjkfjl</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
3. p、c命名空间
<!-- p命名空间注入,可以直接注入属性的值:property -->
<bean id="user" class="com.xawl.pojo.User" p:name="秦将" p:age="18"/>
<!-- c命名空间注入,通过构造器注入:construct-args -->
<bean id="user2" class="com.xawl.pojo.User" c:name="张三" c:age="20"/>
1.2 scope
-
单例范围:scope=“singleton”, 一个对象
-
原型范围:scope=“prototype”, 多个对象
-
web范围:session 、 application 、 request
1.3 基于注解的容器配置
- 基于xml配置文件的自动装配
<!-- 开启注解的支持 -->
<context:annotation-config/>
<bean id="cat" class="com.xawl.pojo.Cat"/>
<bean id="dog" class="com.xawl.pojo.Dog"/>
<!-- autowired:byName setCat1(Cat cat) 根据set后面的名字进行自动装配-->
<bean id="people" class="com.xawl.pojo.People" autowire="byName"></bean>
- byName: 会自动在容器上下文中查找,和自己对象set方法后面的值(id)对应的beanid!
- byType: 会自动在容器上下文中查找,和自己对象属性类型(class)相同的bean
- 基于注解的自动装配
- @Autowired : 自动装备通过类型。名字 优先byType 如果类型无法匹配就找和属性名一致的名字
如果autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”) - @Resource : 自动装配通过名字。类型 优先通过byName,找不到就根据类型去找
- @Qualifier:和@Autowired配合使用(指定名称来装配)
- @Nullable : 字段标记了这个注解,说明这个字段可以为null;
Autowired先类型后名字
Resource先名字后类型
- @Component: 一个组件对象,放在类上,说明这个类被Spring管理了,就是bean!
衍生注解 - @Repository: (数据库,仓库) 注解数据访问层(dao),功能与@Component相同
- @Service: 注解service层 ,功能与@Component相同
- @Controller: 注解controller层,功能与@Component相同
- @Value(“张三”) : 注入属性,相当于
<property name="name" value="狂神">
1.4 使用Java方式配置Spring
- @Configuration+@Bean
//这个也会被spring容器托管,注册到容器中,因为它本身就是一个@Component,
//@Configuration代表这是一个配置类,就和我们之前看到的beans.xml
@Configuration
//@ComponentScan("com.xawl.pojo")
@Import(QinConfig2.class) //导入其他配置类
public class QinConfig {
//注册一个bean,就相当于我们之前写的一个bean标签,
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User user(){
return new User();//就是返回要注入到bean的对象!
}
}
- @Configuration+@ComponentScan(“com.xawl.pojo”)+@Component
@Configuration
@ComponentScan("com.xawl.pojo")
public class QinConfig {
}
@Component
public class User {
private String name;
public String getName() {
return name;
}
//属性注入
@Value("zhangsan")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
2. AOP(面向切面)
代理模式:
2.1 静态代理模式:
抽象角色 : 一般使用接口或者抽象类来实现
真实角色 : 被代理的角色
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
客户 : 使用代理角色来进行一些操作 .
例子:
public class Client {
public static void main(String[] args) {
//房东要出租房子
Host host = new Host();
//代理,中介帮房东租房子,但是呢?代理角一般会有一些附属操作!
Proxy proxy = new Proxy(host);
//那你不用面对房东,直接找中介即可!
proxy.rent();
}
}
//租房
interface Rent {
public void rent();
}
//房东
class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子了!");
}
}
//代理类
class Proxy {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent() {
seeHouse();
host.rent();
hetong();
fare();
}
//看房
public void seeHouse() {
System.out.println("中介带你看房");
}
//签租赁合同
public void hetong() {
System.out.println("签租赁合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
- 静态代理的好处:
-
可以使得我们的真实角色更加纯粹,不再去关注一些公共的事情。
-
公共的业务由代理来完成 ,实现了业务的分工。
-
公共业务发生扩展时变得更加集中和方便。
- 缺点:
- 类多了,多了代理类,工作量变大了。开发效率降低
2.2 动态代理
动态代理的角色和静态代理的一样 .
动态代理的代理类是动态生成的 。 静态代理的代理类是我们提前写好的
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
1. 基于接口的动态代理----JDK动态代理
2. 基于类的动态代理–cglib
现在用的比较多的是 javasist 来生成动态代理
public class Client {
public static void main(String[] args) {
//真是角色
Host host = new Host();
//代理角色: 现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象!
pih.setRent(host);
Rent proxy = (Rent) pih.getProxy();//这里的proxy就是动态生成的,我们并没有写·
proxy.rent();
}
}
//租房
interface Rent {
public void rent();
}
//房东
class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子了!");
}
}
//等我们会用这个类,自动生成代理类!
class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent){
this.rent = rent;
}
/*newProxyInstance(ClassLoader loader, 1.当前类的类加载器
Class<?>[] interfaces, 2.动态代理类需要实现的接口
InvocationHandler h) 3.一个InvocationHandler对象
*/
// 生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
@Override
//处理代理实例,并返回结果
//proxy:代理对象
//method:调用的方法
//args:方法中的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//动态代理的本质就是反射,用反射机制来实现!
Object result = method.invoke(rent,args);
fare();
return result;
}
public void seeHouse(){
System.out.println("中介带看房子");
}
public void fare(){
System.out.println("收中介费");
}
}
2.3 使用Spring实现Aop
- 方式一: 使用Spring的API接口 [主要SpringAPI接口实现]
public class AfterLog implements AfterReturningAdvice {
//returnValue: 返回值
@Override
public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
}
}
public class Log implements MethodBeforeAdvice {
//method: 要执行的目标对象的方法
//args:参数
//target:目标对象
@Override
public void before(Method method, Object[] objects, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了 ");
}
}
<!-- 配置aop:需要导入aop的约束 -->
<aop:config>
<!-- 切入点: expression:表达式,execution(要执行的位置! *****) -->
<aop:pointcut id="pointcut" expression="execution(* com.xawl.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加! -->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
- 方式二: 自定义来实现AOP [主要是切面定义]
public class DiyPointCut {
public void before(){
System.out.println("========方法执行前=======");
}
public void after(){
System.out.println("========方法执行后=======");
}
}
<!-- 自定义类-->
<bean id="diy" class="com.xawl.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面,ref 要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.xawl.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
- 方式三: 使用注解实现
//使用注解方式实现AOP
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.xawl.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("=======方法执行前=======");
}
@After("execution(* com.xawl.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("=======方法执行后=======");
}
//在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入点;
@Around("execution(* com.xawl.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Signature signature = jp.getSignature();//获得签名
System.out.println("signature:"+signature);
//执行方法
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed );
}
}
3. spring整合MyBatis
3.1 整合Mybatis的相关依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!--Spring 操作数据库的话,还需要一个spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
3.2 步骤
- 导入依赖
- 编写实体类
@Data
public class User {
private int id;
private String name;
private String pwd;
}
- 编写配置文件
applicationContext.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">
<import resource="spring-dao.xml"/>
<bean class="com.xawl.dao.UserMapperImpl" id="userMapper">
<property name="sessionTemplate" ref="sqlSession"/>
</bean>
</beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.xawl.pojo"/>
</typeAliases>
<!--<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.xawl.mapper.UserMapper"/>
</mappers>-->
</configuration>
spring-dao.xml:
<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
">
<!--配置数据源-->
<!-- DataSource:使用Spring的数据源替换Mybatis 的配置 c3p0 dbcp druid
我们这里使用Spring提供的JDBC
-->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSl=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"/>
<!-- 绑定Mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/xawl/dao/UserMapper.xml"/>
</bean>
<!--SqlSessionTemplate:就是我们使用的salSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
- 编写mapper
UserMapper.java:
public interface UserMapper {
List<User> select();
}
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xawl.dao.UserMapper">
<select id="select" resultType="User">
select * from mybatis.user
</select>
</mapper>
- 编写mapper的实现类
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSession;
public void setSessionTemplate(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> select() {
return sqlSession.getMapper(UserMapper.class).select();
}
}
- 测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> select = userMapper.select();
for (User user : select) {
System.out.println(user);
}
}
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDfNEZz2-1652594639362)(img_1.png)]
4.spring事务
4.1 声明式事务
<!--
<tx:advice>定义事务通知,用于指定事务属性,其中“transaction-manager”属性指定事务管理器,并通过<tx:attributes>指定具体需要拦截的方法
<tx:method>拦截方法,其中参数有:
name:方法名称,将匹配的方法注入事务管理,可用通配符
propagation:事务传播行为,
isolation:事务隔离级别定义;默认为“DEFAULT”
timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统;
read-only:事务只读设置,默认为false,表示不是只读;
rollback-for:需要触发回滚的异常定义,可定义多个,以“,”分割,默认任何RuntimeException都将导致事务回滚,而任何Checked Exception将不导致事务回滚;
no-rollback-for:不被触发进行回滚的 Exception(s);可定义多个,以“,”分割;
-->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 拦截save开头的方法,事务传播行为为:REQUIRED:必须要有事务, 如果没有就在上下文创建一个 -->
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
<!-- 支持,如果有就有,没有就没有 -->
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 定义切入点,expression为切人点表达式,如下是指定impl包下的所有方法,具体以自身实际要求自定义 -->
<aop:config>
<aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
<!--<aop:advisor>定义切入点,与通知,把tx与aop的配置关联,才是完整的声明事务配置 -->
<aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统