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 基于注解的容器配置

  1. 基于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
  1. 基于注解的自动装配
  • @Autowired : 自动装备通过类型。名字 优先byType 如果类型无法匹配就找和属性名一致的名字
    如果autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”)
  • @Resource : 自动装配通过名字。类型 优先通过byName,找不到就根据类型去找
  • @Qualifier:和@Autowired配合使用(指定名称来装配)
  • @Nullable : 字段标记了这个注解,说明这个字段可以为null;

Autowired先类型后名字

Resource先名字后类型

  1. @Component: 一个组件对象,放在类上,说明这个类被Spring管理了,就是bean!
    衍生注解
  2. @Repository: (数据库,仓库) 注解数据访问层(dao),功能与@Component相同
  3. @Service: 注解service层 ,功能与@Component相同
  4. @Controller: 注解controller层,功能与@Component相同
  5. @Value(“张三”) : 注入属性,相当于<property name="name" value="狂神">

1.4 使用Java方式配置Spring

  1. @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的对象!
    }
}

  1. @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("收中介费");
    }
}

  1. 静态代理的好处:
  • 可以使得我们的真实角色更加纯粹,不再去关注一些公共的事情。

  • 公共的业务由代理来完成 ,实现了业务的分工。

  • 公共业务发生扩展时变得更加集中和方便。

  1. 缺点:
  • 类多了,多了代理类,工作量变大了。开发效率降低

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

  1. 方式一: 使用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>
  1. 方式二: 自定义来实现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>
  1. 方式三: 使用注解实现
//使用注解方式实现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 步骤

  1. 导入依赖
  2. 编写实体类
@Data
public class User {
    private int id;
    private String name;
    private String pwd;
}
  1. 编写配置文件
    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&amp;useUnicode=true&amp;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>

  1. 编写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>
  1. 编写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();
    }
}

  1. 测试
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>
posted on   JAVA开发区  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
点击右上角即可分享
微信分享提示