Spring学习笔记

Spring学习笔记

1、Spring

导包

spring-webmvc(导入这个依赖会自动下载其他依赖)

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.2</version>
</dependency>

spring-jdbc

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.2</version>
</dependency>

spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

2、IOC代码实现

2.1、Spring Hello

新建空的Maven工程,在工程中新建新的Module工程

在pojo新建Hello类

package com.ljh.pojo;
public class Hello {
  private String str;
  public String getStr() {return str;}
  public void setStr(String str) {this.str = str;}
  @Override
  public String toString() {
    return "Hello{" +
            "str='" + str + '\'' +
            '}';
  }
}

resources中新建beans.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="hello" class="com.ljh.pojo.Hello">
    <property name="str" value="Hello Spring"/>
  </bean>
</beans>

bean配置时会在相应文件前有个树叶标志

测试类中

public class MyTest {
  public static void main(String[] args) {
    //获取spring的上下文对象
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Hello hello = (Hello) context.getBean("hello");
    System.out.println(hello.toString());
  }
}
2.2、bean

新建UserDao接口及实现类MysqlImpl、OracleImpl、ServiceImpl

//如MysqlImpl实现类
public class MysqlImpl implements UserDao{
  public void getUser() {
    System.out.println("Mysql实现类");
  }
}

com.ljh.service中新建UserService及实现类UserServiceImpl

package com.ljh.service;

import com.ljh.pojo.UserDao;

public class UserServiceImpl implements UserService{
  private UserDao userDao;

  public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
  }

  public void getUserService() {
    userDao.getUser();
  }
}

bean配置

<?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="mysqlImpl" class="com.ljh.pojo.MysqlImpl"/>
  <bean id="oracleImpl" class="com.ljh.pojo.OracleImpl"/>
  <bean id="serviceImpl" class="com.ljh.pojo.ServiceImpl"/>

  <bean id="userService" class="com.ljh.service.UserServiceImpl">
    <property name="userDao" ref="oracleImpl"/>
  </bean>

</beans>

测试类

public class MyTest {
  public static void main(String[] args) {
    //获取spring的上下文对象
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    UserServiceImpl userService = (UserServiceImpl) context.getBean("userService");
    userService.getUserService();//Oracle实现类
  }
}
2.3、注意

ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);
是获取ApplicationContext,拿到spring容器

context.getBean() 需要什么,就用容器get什么

getBean()括号中是beans.xml的中id的值

<bean id="hello" class="com.ljh.pojo.Hello">
    <property name="str" value="Hello Spring"/>
</bean>
<bean id="userService" class="com.ljh.service.UserServiceImpl">
    <property name="userDao" ref="oracleImpl"/>
</bean>

上面ref和value区别:

ref:引用spring容器中创建好的对象

value:把具体的值赋值给属性,值为基本数据类型

2.4、IOC创建对象
  1. 使用无参构造创建对象,默认。

  2. 使用有参构造

    • 下标赋值:index指的是有参构造中参数的下标,下标从0开始;

      <?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="user" class="pojo.User">
              <constructor-arg index="0" value="xiaoli"/>
          </bean>
      </beans>
      
    • 类型赋值(不建议使用)

    <bean id="user" class="pojo.User">
        <constructor-arg type="java.lang.String" value="xaioli"/>
    </bean>
    
    • 直接通过参数名(容易理解)
    <bean id="user" class="pojo.User">
        <constructor-arg name="name" value="xiaoli"></constructor-arg>
    </bean>
    <!-- 比如参数名是name,则有name="具体值" --> 
    

3、Spring配置

3.1、别名Alias
<bean id="user" class="com.ljh.pojo.User">
    <constructor-arg name="name" value="小李"/>
</bean>
<alias name="user" alias="user2"/>
3.2、Bean的配置
<!--id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的权限名:包名+类型
name:也是别名,而且name可以同时取多个别名,别名之间可以用空格、逗号等分隔 -->
<bean id="user" class="pojo.User" name="u1 u2,u3;u4">
    <property name="name" value="xiaoli"/>
</bean>
3.3、import

import一般用于团队开发使用,它可以将多个配置文件,导入合并为一个

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三(beans.xml)
  • 李四(beans2.xml)
  • 王五(beans3.xml)
  • applicationContext.xml
<import resource="beans.xm1"/>
<import resource="beans2.xml"/>
<import resource="beans3.xm1"/>

4、依赖注入(DI)

4.1、set注入(重点)

实体类pojo

public class Student {
  private String name;
  private Address address;
  private String[] books;
  private List<String> hobbys;
  private Map<String,String> card;
  private Set<String> games;
  private String wife;
  private Properties info;
}
实体类Address及Student的get、set、toString方法省略

beans.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="address" class="com.ljh.pojo.Address">
    <property name="name" value="小李"/>
  </bean>
  <bean id="student" class="com.ljh.pojo.Student">
    <!--第一种,普通值注入,value-->
    <property name="name" value="哈哈哈"/>
    <!--第二种,Bean注入,ref-->
    <property name="address" ref="address"/>
    <!--前两种用的多一点-->
    <!--数组Array-->
    <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,与其余方式有点不同,不是直接用value,而是用entry,里面用key和value-->
    <property name="card">
      <map>
        <entry key="姓名" value="小红"/>
        <entry key="性别" value=""/>
        <entry key="爱好" value="蹦迪"/>
      </map>
    </property>
    <!--set-->
    <property name="games">
      <set>
        <value>LOL</value>
        <value>CF</value>
        <value>PPP</value>
      </set>
    </property>
    <!--null-->
    <property name="wife">
      <null/>
    </property>
    <!--properties,用props内置prop格式-->
    <property name="info">
      <props>
        <prop key="名字">xiaohua</prop>
        <prop key="身份证">111122223333</prop>
        <prop key="手机号">12345665555</prop>
      </props>
    </property>
  </bean>

</beans>

测试类

public class MyText {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Student student = (Student) context.getBean("student");
    System.out.println(student);

    //Student{
    // name='哈哈哈',
    // address=Address{name='小李'},
    // books=[史记, 红楼梦, 时间简史, 西游记],
    // hobbys=[抽烟, 喝酒, 烫头],
    // card={姓名=小红, 性别=女, 爱好=蹦迪},
    // games=[LOL, CF, PPP],
    // wife='null',
    // info={名字=xiaohua, 手机号=12345665555, 身份证=111122223333}
    // }
  }
}
4.2、p、c命名空间
public class User {
  private String name;
  private int age;

  public User() {
  }

  public User(String name, int age) {
    this.name = name;
    this.age = age;
  }
}
//p命名空间不需要加上有参构造
//c命名空间必须加上有参构造
//这里省略了get、set方法
<bean id="user" class="com.ljh.pojo.User"  p:name="小明" p:age="18"/>
<bean id="user2" class="com.ljh.pojo.User" c:age="20" c:name="kscs"/>

测试类

@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    User user = context.getBean("user2", User.class);
    System.out.println(user);
}

注意:使用p和c命名空间需要导入xml约束

<!--加入下面的约束-->
xmlns:p=“http://www.springframework.org/schema/p”
xmlns:c=“http://www.springframework.org/schema/c”
4.3、Bean作用域
  1. 单例模式(默认)

    <bean id="user" class="com.ljh.pojo.User" scope="singleton"></bean>
    
  2. 原型模式: 每次从容器中get的时候,都产生一个新对象!

<bean id="user" class="com.ljh.pojo.User" scope="prototype"></bean>
  1. 其余的request、session、application这些只能在web开放中使用!

5、Bean的自动装配

在Spring中有三种装配方式:

  1. 在xml中显式配置
  2. 在java中显式配置
  3. 隐式的自动装配bean 【重要】
5.1、隐式装配

新建实体类Dog、Cat、Person

beans.xml

<bean id="cat" class="com.ljh.pojo.Cat"/>
<bean id="dog" class="com.ljh.pojo.Dog"/>

<bean id="person" class="com.ljh.pojo.Person" autowire="byType">
    <property name="name" value="小明"/>
</bean>

测试类

@Test
public void Test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Person person = context.getBean("person", Person.class);
    person.getCat().show();
    person.getDog().show();
}

通过 autowire=“byType” 或者 autowire=“byName” 自动装配

  • byType自动装配:byType会自动查找,和自己对象set方法参数的类型相同的bean,保证所有的class唯一(类为全局唯一)
  • byName自动装配:byName会自动查找,和自己对象set对应的值对应的id,保证所有id唯一,并且和set注入的值一致
5.2、注解自动装配

@Autowired【常用】

要使用注解,注意

  1. 导入context约束: xmlns:context="http://www.springframework.org/schema/context"
  2. 配置注解的支持:context:annotation-config/
<?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/context/spring-context.xsd">
	<!--一定要加上下面这句话,添加注解支持-->
    <context:annotation-config/>
</beans>

@Autowired:默认是byType方式,如果匹配不上,就会byName

可以在实体类的属性上面一行添加使用,也可以在set方法上使用

@Nullable 字段标记了这个注解,说明该字段可以为空

如果定义了Autowire的require属性为false,说明这个对象可以为null,否则不允许为空(false表示找不到装配,不抛出异常)

@Autowired不能唯一装配时,需要 @Autowired+@Qualifier

如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候,可以使用@Qualifier(value = “xxx”)去配合使用,指定一个唯一的id对象 。这里的“xxx”指的是在beans.xml中配置的bean的id名

@Resource:默认是byName方式,如果匹配不上,就会byType

6、注解开发

在spring4之后,使用注解开发,必须要保证aop包的导入

<?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/context/spring-context.xsd">

    <context:annotation-config/>

</beans>
6.1、Bean

【@Component】

<!--指定要扫描的包,这个包下面的注解才会生效,别只扫一个com.ljh.pojo包--> 
<context:component-scan base-package="com.ljh"/> 
<context:annotation-config/>

注: 有了< context:component-scan>,另一个< context:annotation-config/>标签可以移除掉,因为已经被包含进去了。

//@Component 组件
//等价于<bean id="user" class="com.ljh.pojo.User"/> 
@Component
public class User {  
     public String name ="小明";
}
6.2、属性注入

【@Value】

@value("小明") 
public String name;
6.3、衍生注解

@Component有几个衍生注解,会按照web开发中,mvc架构中分层。

  • dao 【@Repository】
  • service【@Service】
  • controller【@Controller】

这四个注解的功能是一样的,都是代表将某个类注册到容器中

6.4、自动装配

@Autowired:默认是byType方式,如果匹配不上,就会byName

@Nullable:字段标记了这个注解,说明该字段可以为空

@Resource:默认是byName方式,如果匹配不上,就会byType

6.5、作用域注解

【@scope】

//原型模式prototype,单例模式singleton
//scope("prototype")相当于<bean scope="prototype"></bean>
@Component 
@scope("prototype")
public class User { }
6.6、使用
  • xml用来管理bean
  • 注解只用来完成属性的注入
  • 要开启注解支持

7、使用Java代码配置Spring

不使用Spring的xml配置,完全交给java来做!

实体类

//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中 
@component 
public class User { 
    private String name;
    
    public String getName() { 
    	return name; 
    } 
    //属性注入值
    @value("xiaoming')  
    public void setName(String name) { 
    	this.name = name; 
    } 
    @Override 
    public String toString() { 
        return "user{" + 
        "name='" + name + '\''+ 
        '}'; 
    } 
}

在com.ljh下新建包config,用Java代码配置spring

//这个也会Spring容器托管,注册到容器中,因为他本米就是一个@Component 
// @Configuration表这是一个配置类,就像我们之前看的beans.xml,类似于<beans>标签
@Configuration 
@componentScan("com.ljh.pojo") //开启扫描,不扫描也能出来结果
public class LjhConfig { 
    //注册一个bean , 就相当于我们之前写的一个bean 标签 
    //这个方法的名字,就相当于bean 标签中的 id 属性 ->getUser
    //这个方法的返同值,就相当于bean 标签中的class 属性 ->User
    
    @Bean 
    public User getUser(){ 
    	return new User(); //就是返回要注入到bean的对象! 
    } 
}

测试类

@Test
public void Test() {
    ApplicationContext context = new AnnotationConfigApplicationContext(LjhConfig.class);
    User user = (User) context.getBean("getUser");
    System.out.println(user.getName());
}

注:这里使用的是AnnotationConfigApplicationContext

8、代理模式

8.1、静态代理

在不修改目标对象的功能前提下,对目标功能扩展 。

缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象与代理对象都要维护。

接口

public interface Host {
  void rent();
}

实现类

public class Hoster implements Host{
  public void rent() {
    System.out.println("客户租房子");
  }
}

代理

public class Proxy {
  public Host host;

  public Proxy() {
  }

  public Proxy(Host host) {
    this.host = host;
  }

  public void rent() {
    seeHouse();
    host.rent();
    fare();
  }

  public void seeHouse() {
    System.out.println("看房子");
  }
  public void fare() {
    System.out.println("出钱");
  }
}

测试类

public void Test() {
    Host host = new Hoster();
    Proxy proxy = new Proxy(host);
    proxy.rent();
}
8.2、动态代理

1、Proxy:代理
2、InvocationHandler:调用处理程序

代理类所在包:java.lang.reflect.Proxy

接口

public interface Host {
  void rent();
}

实现类

public class Hoster implements Host{
  public void rent() {
    System.out.println("客户租房子");
  }
}

通用代理类

public class ProxyInvocationHandler implements InvocationHandler {

	// 被代理的接口
	public Object target;

	public void setTarget(Object target) {
		this.target = target;
	}

	// 得到生成的代理类
	public Object getProxy() {
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}

	// 处理代理实例并返回结果
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 动态代理的本质,就是使用反射机制实现的
		// invoke()执行它真正要执行的方法
		Object result = method.invoke(target, args);
		return result;
	}

}

注:通用代理类可认作一个工具类

测试类

public void Test() {
    Host host = new Hoster();

    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    pih.setTarget(host);

    Host proxy = (Host) pih.getProxy();
    proxy.rent();
}

9、AOP

AOP就是在不改变原有代码的情况下,去添加新的功能,类似于代理

添加依赖

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>
9.1、原生Spring实现

添加AOP约束

xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">

在com.ljh.service中编写UserService和UserServiceImpl

public interface UserService {
  void add();
  void delete();
  void update();
  void select();
}
public class UserServiceImpl implements UserService{
  public void add() {
    System.out.println("添加了一条数据");
  }

  public void delete() {
    System.out.println("删除了一条数据");
  }

  public void update() {
    System.out.println("更新了一条数据");
  }

  public void select() {
    System.out.println("查询了一条数据");
  }
}

在com.ljh.log中新建AfterLog和BeforeLog

package com.ljh.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
  //method:要执行的目标对象的方法
  //args:参数
  //target:目标对象
  //returnValue:返回值
  public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法,返回值是:"+returnValue);
  }
}
package com.ljh.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {
  public void before(Method method, Object[] args, Object target) throws Throwable {
    System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法");
  }
}

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"
       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/aop
		    https://www.springframework.org/schema/aop/spring-aop.xsd">


  <bean id="userService" class="com.ljh.service.UserServiceImpl"/>
  <bean id="afterLog" class="com.ljh.log.AfterLog"/>
  <bean id="beforeLog" class="com.ljh.log.BeforeLog"/>

  <!--配置aop,一定要导入aop约束-->
  <aop:config>
    <!--pointcut切入点,其中参数expression:表达式,execution(返回类型 要执行的位置)-->
    <!--com.ljh.service.UserServiceImpl.*(..) -> UserServiceImpl类下的所以方法(任意参数)-->
    <aop:pointcut id="pointcut" expression="execution(* com.ljh.service.UserServiceImpl.*(..))"/>
    <!--执行环绕增加-->
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
  </aop:config>


</beans>

测试

@Test
  public void Test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = context.getBean("userService", UserService.class);
    userService.delete();
}

结果

com.ljh.service.UserServiceImpl执行了delete方法
删除了一条数据
com.ljh.service.UserServiceImpl执行了delete方法,返回值是:null
9.2、自定义类实现

新建com.ljh.diy的自定义类DiyPointcut

public class DiyPointcut {
  public void before() {
    System.out.println("====执行前====");
  }

  public void after() {
    System.out.println("====执行后====");
  }
}

UserService和UserServiceImpl不重复写,和上面一样

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"
       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/aop
		    https://www.springframework.org/schema/aop/spring-aop.xsd">


  <bean id="userService" class="com.ljh.service.UserServiceImpl"/>
  <bean id="diy" class="com.ljh.diy.DiyPointcut"/>
    
  <aop:config>
    <!--自定义切面-->
    <aop:aspect ref="diy">
      <aop:pointcut id="pointcut" expression="execution(* com.ljh.service.UserServiceImpl.*(..))"/>
      <aop:after method="after" pointcut-ref="pointcut"/>
      <aop:before method="before" pointcut-ref="pointcut"/>
    </aop:aspect>
  </aop:config>
    
</beans>
9.3、注解实现

在diy包中新建DiyAnnovation类

package com.ljh.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class DiyAnnotation {
  @Before("execution(* com.ljh.service.UserServiceImpl.*(..))")
  public void before() {
    System.out.println("====执行前====");
  }

  @After("execution(* com.ljh.service.UserServiceImpl.*(..))")
  public void after() {
    System.out.println("====执行后====");
  }

  @Around("execution(* com.ljh.service.UserServiceImpl.*(..))")
  public void round(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("---环绕前---");
    Object proceed = joinPoint.proceed();
    System.out.println("---环绕后---");
  }
}

UserService和UserServiceImpl不重复写,和上面一样

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"
       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/aop
		    https://www.springframework.org/schema/aop/spring-aop.xsd">


  <bean id="userService" class="com.ljh.service.UserServiceImpl"/>
  <bean id="diy" class="com.ljh.diy.DiyAnnotation"/>
  <!-- 开启自动代理
      实现方式:默认JDK (proxy-targer-class="fasle") cgbin (proxy-targer-class="true")-->
  <aop:aspectj-autoproxy/>

</beans>

测试类

@Test
  public void Test() {

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = context.getBean("userService", UserService.class);
    userService.add();

}

结果

---环绕前---
====执行前====
添加了一条数据
====执行后====
---环绕后---

10、Spring整合Mybatis

就是MyBatis-Spring:http://mybatis.org/spring/zh/index.html

10.1、方式一【掌握】

在pom.xml中添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.7.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.14</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>

注:我在这里导入最新版的spring-jdbc时报错,这里降低了版本

由于静态资源过滤,出现识别不了xml文件,添加下面的代码

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

与mybatis相同,新建com.ljh.mapper和com.ljh.pojo

第一步新建Student实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
  private int id;
  private String name;
  private String phone;
}

相同的是新建StudentMapper接口及StudentMapper.xml,不同的是整合时还需要Student Mapper接口实现类

StudentMapper接口

public interface StudentMapper {
  List<Student> getStudentList();
}

StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ljh.mapper.StudentMapper">

  <!--id里面是接口里面命名的函数-->
  <select id="getStudentList" resultType="student">
    select * from javatest.student
  </select>

</mapper>

Student Mapper接口实现类

public class StudentMapperImpl implements StudentMapper{

  private SqlSessionTemplate sqlSession;

  public void setSqlSession(SqlSessionTemplate sqlSession) {
    this.sqlSession = sqlSession;
  }

  public List<Student> getStudentList() {
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    return mapper.getStudentList();
  }
}

注意:StudentMapper.xml里面的id和Student Mapper接口实现类里面的重写方法名getStudentList必须和StudentMapper接口中所起的名称一致,否则直接报错

接下来在resources文件夹下新建mybatis-config.xml、spring-dao.xml、applicationContext.xml

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>

  <settings>
    <setting name="logImpl" value="STDOUT_LOGGING" />
  </settings>

  <typeAliases>
    <package name="com.ljh.pojo"/>
  </typeAliases>

</configuration>

spring-dao.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">


  <!--DataSource:使用Spring的数据源替换Mybatis的配置 其他数据源:c3p0、dbcp、druid
		这里使用Spring提供的JDBC: org.springframework.jdbc.datasource.DriverManagerDataSource -->
  <!--dataSource数据源-->
  <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/javatest?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=UTC&amp;useSSL=false"/>
    <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/ljh/mapper/*.xml"/>
  </bean>
  <!-- sqlSessionTemplate 就是之前使用的:sqlsession -->
  <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!-- 只能使用构造器注入sqlSessionFactory 原因:它没有set方法-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
  </bean>

</beans>

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
		    https://www.springframework.org/schema/beans/spring-beans.xsd">


  <import resource="spring-dao.xml"/>

  <bean id="studentMapper" class="com.ljh.mapper.StudentMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
  </bean>

</beans>

注意:在mybatis-config.xml中只需要起别名或设置属性

spring-dao.xml是一个固定的代码模板

applicationContext.xml把spring-dao.xml导入,只需要配置bean即可

测试

@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    StudentMapper studentMapper = (StudentMapper) context.getBean("studentMapper");
    //    StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);  和上面的代码相同
    List<Student> studentList = studentMapper.getStudentList();
    for (Student student : studentList) {
        System.out.println(student);
    }
}

结果

Student(id=1, name=司马迁, phone=10086)
Student(id=2, name=胡歌, phone=123456)
Student(id=3, name=蔡徐坤, phone=12346)
Student(id=4, name=冯森, phone=12367)
Student(id=5, name=侯亮平, phone=12333)
10.2、方式二【方便】

主要用SqlSessionDaoSupport

替换掉上面的StudentMapperImpl,这里写为StudentMapperImpl2

与以前不同的是现在继承SqlSessionDaoSupport, SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法 。

package com.ljh.mapper;

import com.ljh.pojo.Student;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class StudentMapperImpl2 extends SqlSessionDaoSupport implements StudentMapper{
  public List<Student> getStudentList() {
//    SqlSession sqlSession = getSqlSession();
//    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//    return mapper.getStudentList();
    return getSqlSession().getMapper(StudentMapper.class).getStudentList();
  }
}

之后在applicationContext.xml中注册bean

<bean id="studentMapper2" class="com.ljh.mapper.StudentMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

测试

@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    StudentMapper studentMapper = (StudentMapper) context.getBean("studentMapper2");
    //    StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
    List<Student> studentList = studentMapper.getStudentList();
    for (Student student : studentList) {
        System.out.println(student);
    }
}

11、声明式事务

要么都成功,要么都失败!

接口类

public interface StudentMapper {
  List<Student> getStudentList();
  int addStudent(Student student);
  int deleteStudent(int id);
}

接口实现类

public class StudentMapperImpl2 extends SqlSessionDaoSupport implements StudentMapper{
  public List<Student> getStudentList() {
//    SqlSession sqlSession = getSqlSession();
//    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//    return mapper.getStudentList();

    Student student = new Student(7,"螃蟹","75642");
    addStudent(student);

    deleteStudent(6);

    return getSqlSession().getMapper(StudentMapper.class).getStudentList();
  }

  public int addStudent(Student student) {
    return getSqlSession().getMapper(StudentMapper.class).addStudent(student);
  }

  public int deleteStudent(int id) {
    return getSqlSession().getMapper(StudentMapper.class).deleteStudent(id);
  }
}

这里若是add方法无误,delete方法出现错误,会把添加数据库语句执行,不执行删除语句。

应该是出现错误后,add方法回滚,delete方法不执行。

想要实现,在spring-dao.xml配置事务即可。

汇总后的spring-dao.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd">


  <!--DataSource:使用Spring的数据源替换Mybatis的配置 其他数据源:c3p0、dbcp、druid
		这里使用Spring提供的JDBC: org.springframework.jdbc.datasource.DriverManagerDataSource -->
  <!--dataSource数据源-->
  <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/javatest?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=UTC&amp;useSSL=false"/>
    <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/ljh/mapper/*.xml"/>
  </bean>
  <!-- sqlSessionTemplate 就是之前使用的:sqlsession -->
  <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!-- 只能使用构造器注入sqlSessionFactory 原因:它没有set方法-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
  </bean>

  <!--声明式事务-->
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <constructor-arg ref="dataSource" />
  </bean>
  <!--结合aop实现事务织入-->
  <!--配置事务的通知类-->
  <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--给哪些方法配置事务-->
    <!--配置事务的传播特性:propagation,默认为REQUIRED-->
    <tx:attributes>
<!--      <tx:method name="add" propagation="REQUIRED"/>-->
<!--      <tx:method name="delete" propagation="REQUIRED"/>-->
<!--      <tx:method name="update" propagation="REQUIRED"/>-->
<!--      <tx:method name="query" read-only="true"/>-->
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>
  <!--配置事务切入-->
  <aop:config>
    <aop:pointcut id="txpointcut" expression="execution(* com.ljh.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txpointcut"/>
  </aop:config>

</beans>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值