Spring
1.spring简介和学习信息
- spring官网:
-
githup源码地址:
可以通过官网的githup图标连接过去
-
maven依赖:可以直接导包spring-webmvc,因为它能自动帮我们导很多其他依赖包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.9</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.9</version> </dependency>
2.spring优点
- spring是免费开源框架(容器)
- spring是轻量级的,非入侵的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务处理,对框架整合的支持
总结:spring是控制反转,面向切面编程的框架
3.spring入门
pojo类
package com.ting.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 + '\'' +
'}';
}
}
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">
<!--配置文件来源spring官网文档:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
-->
<!--传统的创建对象:
类型 变量名 = new 对象
spring创建对象:
id 相当于变量名,class相当于new的那个对象,properties中的值相当于赋值
-->
<bean id="hello" class="com.ting.pojo.Hello">
<!--此处的赋值是调用的Hello类中的setter方法,如果没有set方法,赋值会报错-->
<property name="str" value="spring"/>
</bean>
</beans>
测试类:
package com.ting.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest {
/**
*
*/
@Test
public void Hello()throws Exception{
// 可以传入多个配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// Hello hello = (Hello) context.getBean("hello");
Hello hello = context.getBean("hello", Hello.class);
System.out.println(hello);
}
}
4.ioc创建对象
4.1使用无参构造创建对象(默认方法)
4.1.1进行添加配置文件时,idea设置spring配置文件的支持,操作如下:
设置之后,一个类被spring管理后,有提示,可以通过点击进行到配置文件中的跳转:
pojo类:
package com.ting.pojo;
public class User {
private String name;
public User() {
System.out.println("调用了User的无参构造方法");
}
public User(String name) {
this.name = name;
}
public void show() {
System.out.println("name = " + name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
无参构造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="user" class="com.ting.pojo.User">
<property name="name" value="ting"/>
</bean>
</beans>
无参构造测试类:
@Test
public void TestUser()throws Exception{
// 获取容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取user对象
User user = context.getBean("user", User.class);
user.show();
}
4.2有参构造(3种方式)
-
使用索引
<!--有参构造,使用下标--> <bean id="user" class="com.ting.pojo.User"> <constructor-arg index="0" value="use index"/> </bean>
-
使用类型(不推荐)
<!--通过类型创建对象,不推荐--> <bean id="user" class="com.ting.pojo.User"> <constructor-arg type="java.lang.String" value="use type"/> </bean>
-
使用名字(常用,推荐)
<!--通过名称创建对象,推荐且常用--> <bean id="user" class="com.ting.pojo.User"> <constructor-arg name="name" value="use name"/> </bean>
注意:spring在加载配置文件时,会将配置文件中的所有bean都进行创建对象
5.spring配置
5.1别名
alias创建bean的别名设置:
<!--alias设置别名-->
<alias name="user" alias="user2"/>
测试类中创建对象是可以用user和user2进行获取bean
5.2bean配置
<!--bean的属性
id:唯一标识符,相当于对象名
class:全限定名,包名+类名
name:别名,可以用空格,逗号,分号,进行别名的分隔,能同时起多个别名
scope:可以设置创建对象是不是单例,默认单例
-->
<bean id="user" class="com.ting.pojo.User" name="u u1,u2;u3">
<constructor-arg name="name" value="use name"/>
</bean>
可以用u,u1,u2,u3以及user获取bean,比alias强大
5.3import
用于团队开发,将多个配置文件导入合成一个.如张三,李四,王五三个人开发三个功能使用了3个不同名字的beans.xml,可以都导入到指定的配置文件中,如:applicationContext.xml,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">
<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
</beans>
6.DI依赖注入
6.1环境搭建
-
pojo类
package com.ting.pojo; // 需要get和set方法,自己补充 public class Address { private String address; }
package com.ting.pojo; import java.util.*; // 需要get和set方法,自己补充 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; }
-
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="student" class="com.ting.pojo.Student"> <property name="name" value="ting"/> </bean> </beans>
-
测试类
@Test public void testDI()throws Exception{ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = context.getBean("student", Student.class); System.out.println(student.getName()); }
6.2各种类型的set注入(重点)
<bean id="address" class="com.ting.pojo.Address">
<property name="address" value="北京"/>
</bean>
<bean id="student" class="com.ting.pojo.Student">
<!--简单注入-->
<property name="name" value="ting"/>
<!--引用注入-->
<property name="address" ref="address"/>
<!--数组-->
<property name="books">
<array>
<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="11111122222233333344"/>
<entry key="银行卡" value="5556667889900067784"/>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
</set>
</property>
<!--properties-->
<property name="info">
<props>
<prop key="学号">1121821</prop>
<prop key="姓名">ting</prop>
<prop key="性别">男</prop>
</props>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
</bean>
测试类和结果:
@Test
public void testDI()throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = context.getBean("student", Student.class);
System.out.println(student);
/*
结果:
Student{
name='ting',
address=Address{address='北京'},
books=[三国, 红楼],
hobbys=[抽烟, 喝酒, 烫头],
card={身份证=11111122222233333344,
银行卡=5556667889900067784},
games=[LOL, BOB],
wife='null',
info={学号=1121821, 性别=男, 姓名=ting}}
*/
}
6.3其他注入方式
-
c命名空间和p命名空间注入
pojo类:
c命名空间相当于构造方法注入,使用时需要声明有参构造和无参构造
public class User { private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } }
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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--p命名空间注入--> <bean id="user" class="com.ting.pojo.User" p:name="张三" p:age="23"/> <!--c命名空间注入--> <bean id="user2" class="com.ting.pojo.User" c:name="李四" c:age="24"/> </beans>
测试类:
@Test public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); // p命名空间注入 User user = context.getBean("user", User.class); System.out.println(user); // c命名空间注入 User user2 = context.getBean("user2", User.class); System.out.println(user2); }
注意:p和c命名空间不能直接使用,需要导入约束
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
6.4构造器注入
参考前面讲解4.2有参构造
6.5bean的作用域
-
单例模式(spring的默认机制)
<bean id="user" class="com.ting.pojo.User" p:name="张三" p:age="23" scope="singleton"/>
-
原型模式:每次get的时候都会获取一个新对象
<bean id="user" class="com.ting.pojo.User" p:name="张三" p:age="23" scope="prototype"/>
-
其余的request,session,application这些只能在web开发中使用
7.bean的自动装配
spring在上下文中自动寻找,并自动给bean装配
spring的自动转配有三种:
- xml中显示装配
- java中显示配置
- 隐式的自动装配(重点)
7.1测试
xml显式配置:
<bean id="cat" class="com.ting.pojo.Cat"/>
<bean id="dog" class="com.ting.pojo.Dog"/>
<bean id="people" class="com.ting.pojo.People">
<property name="name" value="zhangsan"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
7.2byName和byType
<bean id="cat" class="com.ting.pojo.Cat"/>
<bean id="dog" class="com.ting.pojo.Dog"/>
<!--
byName:会自动在容器上下文查找和自己对象set方法后面的值相对应的beanid
byType:会自动在容器上下文查找和自己对象属性类型相同的bean
-->
<bean id="people" class="com.ting.pojo.People" autowire="byName">
<property name="name" value="zhangsan"/>
</bean>
<bean id="people2" class="com.ting.pojo.People" autowire="byType">
<property name="name" value="zhangsan"/>
</bean>
小结:
- byName:需要保证所有bean的id唯一,并且bean需要和自动注入的id和set方法的参数一致
- byType:需要保证所有bean的class唯一,并且bean需要和自动注入的属性类型一致
7.3使用注解装配
使用解的注意事项:
-
需要导入约束
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context https://www.springframework.org/schema/beans/spring-context.xsd
-
需要开启注解的支持
<context:annotation-config/>
整体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: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/beans/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired:自动装配
-
@Autowired可以用在属性上,也可以用在set方法上
-
如果自动装配的属性在ioc容器中存在,且符合byName的规则,使用@Autowired可以不用写set方法
-
@Autowired注解内容:
public @interface Autowired { boolean required() default true; }
注意:如果显示定义了required为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
-
如果装配环境比较复杂,不能通过@Autowired注解指定唯一的对象进行装配,我们可以通过@Qualifier(value = “xml中配置的beanid”)来进行唯一装配
public class People { @Autowired @Qualifier(value = "cat11") private Cat cat; @Autowired @Qualifier(value = "dog11") private Dog dog; private String name; }
<bean id="cat" class="com.ting.pojo.Cat"/> <bean id="cat11" class="com.ting.pojo.Cat"/> <bean id="dog11" class="com.ting.pojo.Dog"/> <bean id="dog" class="com.ting.pojo.Dog"/>
-
@Resource(功能强大,但是使用较少)
-
java原生的注解,也能用于自动装配,会根据名字或者class进行自动装配
-
@Resource(name = “cat11”)可以通过name直接beanid实现唯一装配
public class People { // @Autowired // @Qualifier(value = "cat11") @Resource(name = "cat11") private Cat cat; @Autowired @Qualifier(value = "dog11") private Dog dog; private String name; }
-
小结:
@Resource和@Autowired区别:
@Nullable:为空
- 标了这个注解数据这个字段可以为null,且不会报错
8.使用注解开发
- spring4之后想要使用注解,必须导入aop依赖包,在导入webmvc时能自动导入,如果注解不能使用可以查看这个包是否存在
-
使用直接需要导入context约束和开启注解支持
<?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:component-scan base-package="com.ting"/> <context:annotation-config/> </beans>
bean注入
以下几个注解功能相同:
表示这个bean交给spring管理,是spring的一个组件,相当于配置文件中的<bean id="user" class="com.ting.pojo.User">
- @Component:通用注解
- @Controller:用于controller层
- @Service::用于service层
- @Repository:用于dao层
属性注入
@Value:用于属性值的注入相当于配置文件中的<property name="name" value="zhangsan"/>
自动装配注解(参考7.3)
作用域注解
@Scope("prototype") //作用域注解,用于bean
小结:
xml和注解的优缺点:
- xml更万能,便于维护,适用于所有场景
- 注解只适用于自己的类,维护相对复杂
最佳实践:
- 注解用于完成属性的注入
- xml用于管理bean
注解应用时需要注意:
想要注解生效,必须开启注解的支持,如果用包扫描的方式,需要注意扫描的包路径
<!--开启注解的包扫描,会扫描包下的注解-->
<context:component-scan base-package="com.ting"/>
<!--开启注解的支持-->
<context:annotation-config/>
9.使用javaConfig配置类方式配置spring
这种是纯java的配置方式,全部使用注解,不再使用xml配置文件,这种方式在springboot中随处可见
pojo类
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class User {
@Value("zhangsan")
private String name;
}
主配置类
package com.ting.config;
import com.ting.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
// @Configuration也是交给spring管理
//标志这个类是一个配置类,相当于beans.xml配置文件
@Configuration
@ComponentScan("com.ting.pojo") // 包扫描
@Import(MyConfig2.class) // 引入其他的配置类
public class MyConfig {
// 注册一个bean,就相当于配置文件中的一个bean
// 方法名相当于xml中的id属性,返回值相当于xml中的class属性
@Bean
public User getUser() {
// 返回要注入的bean对象
return new User();
}
}
引用配置类
package com.ting.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig2 {
@Bean
public String testConfig() {
return "测试@Import()注解";
}
}
测试类:
import com.ting.config.MyConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
@Test
public void test01() {
//如果完全用配置类的方式去做,需要用AnnotationConfigApplicationContext来获取上线文,通过bean对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
// User user = (User) context.getBean("getUser");
String user = (String) context.getBean("testConfig");
System.out.println(user);
}
}
注意:
如果完全用配置类的方式去做,需要用AnnotationConfigApplicationContext来获取上线文,通过bean对象加载
10.代理模式
10.1静态代理
角色分析:
- 抽象角色: 一般会使用接口或者抽象类来解决
- 真实角色: 被代理的角色
- 代理角色: 代理真实角色,代理真实角色后会做一些附属操作
- 客户:使用的人
代码开发步骤:
接口编写
public interface Rent {
void rent();
}
真实角色
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子");
}
}
代理角色
public class Proxy implements Rent {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent() {
seeHost();
host.rent();
hetong();
fare();
}
public void seeHost() {
System.out.println("中介带你看房子");
}
public void hetong() {
System.out.println("中介和你签合同");
}
public void fare() {
System.out.println("中介收取中介费");
}
}
客户测试
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy(new Host());
proxy.rent();
}
}
代理模式的好处:
- 可以使真实角色更纯粹,不用关注一些公共的业务
- 公共业务交给代理角色,实现业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色,产生一个代理角色,代码量翻倍,开发效率低下
10.2动态代理
- 动态代理和静态代理的角色相同
- 动态代理的的代理类是动态生成的
- 动态代理分两大类:基于接口和基于类的
- 基于接口:jdk动态代理
- 基于类:cglib
- java字节码实现:javasist
需要了解两个类:
Proxy:代理类
InvocationHandler:调用处理程序
接口:
package com.ting.demo_03;
public interface Rent {
void rent();
}
实体类:
package com.ting.demo_03;
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子");
}
}
代理是处理类(通用的):
package com.ting.demo_03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
// 代理处理的角色
private Object target;
// 设置代理处理角色,供下方获取代理类使用
void setTarget(Object target) {
this.target = target;
}
// 获取代理对象实例
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;
}
}
客户端:
package com.ting.demo_03;
public class Client {
public static void main(String[] args) {
// 真实角色
Host host = new Host();
// 代理类处理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
// 设置代理那个角色
pih.setTarget(host);
// 获取代理角色
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
11. AOP
11.1aop的常用词:
11.2spring使用aop
spring使用aop必须导入织入的包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
11.3spring aop的使用方式
方式一:使用spring API接口
-
编写接口
package com.ting.service; public interface UserService { void add(); void delete(); void update(); void select(); }
-
编写实现类
package com.ting.service; 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("查询一个用户"); } }
-
编写增强类
前置日志:
package com.ting.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class BeforeLog implements MethodBeforeAdvice { // method 要执行目标对象的方法 // objects 需要出入的参数,即args // o 传入的目标对象 // before的源码:void before(Method method, Object[] args, @Nullable Object target) public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(method.getClass().getName() + "执行了" + method.getName() + "方法" ); } }
后置日志:
package com.ting.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice { // returnValue方法返回值 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(method.getName() + "被执行了,返回值是:" + returnValue); } }
-
将实现类和增强类在配置文件中注册,编写配置文件进行aop的切入
在进行aop配置编写的时候必须先导入aop的约束:
xmlns:aop="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd<?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.ting.service.UserServiceImpl"/> <bean id="afterLog" class="com.ting.log.AfterLog"/> <bean id="beforeLog" class="com.ting.log.BeforeLog"/> <!--添加aop配置:添加配置前必须新增aop的约束 xmlns:aop="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd --> <aop:config> <!--配置切点,可以配置多个--> <aop:pointcut id="pointcut" expression="execution(* com.ting.service.UserServiceImpl.*(..))"/> <!--配置通知(前置)--> <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> </beans>
-
编写测试类,获取上下文进行aop测试
import com.ting.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { // 获取容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); } }
方式二:自定义类实现aop
-
自定义增强类
package com.ting.div; public class DivLog { public void beforeLog() { System.out.println("========切入到方法之前执行==========="); } public void afterLog() { System.out.println("========切入到方法之后执行==========="); } }
-
编写配置文件,将增强类作为切面,各个方法对应切入到各切点中
<!--方式二:自定义类进行aop--> <!--在spring注册自定义的增强类--> <bean id="div" class="com.ting.div.DivLog"/> <aop:config> <!--配置切点--> <aop:pointcut id="pointcut" expression="execution(* com.ting.service.UserServiceImpl.*(..))"/> <!--配置切面--> <aop:aspect ref="div"> <aop:before method="beforeLog" pointcut-ref="pointcut"/> <aop:after method="afterLog" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
-
接口,实现类,测试类和方式一中相同
方式三:使用注解实现AOP
-
在配置文件中开启aop的注解支持
<!--方式三:使用注解进行过aop--> <!--开启aop注解支持--> <aop:aspectj-autoproxy/> <!--将自定义的增强类,注册到spring容器中,也可以用下面spring的注解方法向spring容器注册--> <bean id="annotionDiv" class="com.ting.div.AnnotionDiv"/> <!--开启spring的注解支持--> <!-- <context:annotation-config/>--> <!-- <context:component-scan base-package="com.ting"/>-->
-
自定义一个增强类,用注解@Aspect标注为切面
-
编写对应的方法,分别将对应的切点导入,例如:@Before(“execution(* com.ting.service.UserServiceImpl.*(…))”)
package com.ting.div; 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; import org.springframework.stereotype.Component; // 方式三,使用注解方式实现AOP @Aspect // 此注解将这个类标记成切面 @Component //将这个类交给spring管理 public class AnnotionDiv { @Before("execution(* com.ting.service.UserServiceImpl.*(..))") public void before() { System.out.println("****方法执行前****"); } @After("execution(* com.ting.service.UserServiceImpl.*(..))") public void after() { System.out.println("*****方法执行后******"); } // 环绕通知,可以传入一个参数作为一个连接点,用于方法的执行 @Around("execution(* com.ting.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("*************环绕通知**************"); System.out.println("环绕前"); // 方法执行 System.out.println(jp.getSignature()); // 获取方法签名 Object proceed = jp.proceed(); System.out.println("环绕后"); } }
-
执行测试方法
测试结果:
12.spring整合mybatis
12.1整合步骤
- 导入依赖jar包
- junit
- mybatis
- mysql
- spring相关
- aop织入
- mybatis-spring
- 编写配置文件
- 测试
12.2回顾mybatis
-
编写实体类
package com.ting.pojo; import lombok.Data; @Data public class User { private int id; private String name; private String pwd; }
-
编写核心配置文件
<?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.ting"/> </typeAliases> <environments default="test"> <environment id="test"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/ting/mapper/UserMapper.xml"/> </mappers> </configuration>
-
编写接口和接口的xml配置文件
package com.ting.mapper; import com.ting.pojo.User; import java.util.List; public interface UserMapper { List<User> selectUser(); }
<?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.ting.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from mybatis.user </select> </mapper>
-
将接口的xml注册到核心配置文件中
-
编写测试类
import com.ting.mapper.UserMapper; import com.ting.pojo.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyTest { @Test public void test01() throws IOException { String resources = "mybatis-config.xml"; InputStream in = Resources.getResourceAsStream(resources); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.selectUser(); for (User user : users) { System.out.println(user); } } }
12.3spring和mybatis整合
方式一:
pom文件版本
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
<!--在builder中配置资源,防止找不到-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
-
在spring-dao.xml配置文件中配置数据源,取代mybatis配置的数据源
-
在spring-dao.xml配置文件中配置sqlSessionFactory
-
在spring-dao.xml配置文件中配置sqlSessionTemplate,替代sqlSession
完整的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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--引入数据源,替代mybatis中的数据源--> <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?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!--sqlSessionFactory创建--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--加载数据源--> <property name="dataSource" ref="dataSource"/> <!--装配mybatis的配置文件,spring可以完全取代mybatis的配置--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!--加载mapper的配置文件--> <property name="mapperLocations" value="classpath:com/ting/mapper/*.xml"/> </bean> <!--通过spring的SqlSessionTemplate创建sqlsession, 由于没有set方法,需要使用构造方法将sqlSessionFactory注入到SqlSessionTemplate中--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> </beans>
-
创建接口实现类,用来进行进行接口方法的实现
package com.ting.mapper; import com.ting.pojo.User; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; public class UserMapperImpl implements UserMapper { private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } }
-
在applicationContext.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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <import resource="spring-dao.xml"/> <bean id="userMapper" class="com.ting.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>
-
测试,应用sping的配置文件,调用接口的方法实现
@Test public void test02() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } }
方式二(简化):
实现类需要继承SqlSessionDaoSupport类,继承之后可以使用getSqlSession()方法来获取sqlSession,进行响应的操作.
接口实现类:
package com.ting.mapper;
import com.ting.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> selectUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
spirng核心配置文件注册的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"
xmlns:aop="http://www.springframework.org/schema/aop"
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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.ting.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
<!--通过继承SqlSessionDaoSupport来进行mybatis的整合-->
<bean id="userMapper2" class="com.ting.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
因为sqlSession可以通过继承SqlSessionDaoSupport类来获取,索引spring-dao.xml的配置文件中,都不需要注册sqlSession的bean
13.声明式事务
声明式事务主要使用的是spring的aop进行事务的切入,对不同的方法进行增加事务,保证数据的一致性,具体操作是修改spring-dao.xml的配置文件,增加事务的使用和aop的事务切入
-
使用事务,需要先增加事务的约束
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
-
配置中增加事务管理,引入数据源
<!--配置声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
-
配置事务的通知,通过aop的织入方式将事务织入到不同的方法中
<!--结合sprin的aop织入--> <!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--给方法配置事务--> <!--配置事务的传播特性:propagation,默认是"REQUIRED",一般使用默认值就行,代表存在事务的时候使用,不存在事务时创建事务--> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="select*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
-
通过spring的aop配置切点,将事务切入
<!--配置aop切入事务--> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.ting.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
-
进行测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } } }
-
完整的spirng-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:context="http://www.springframework.org/schema/context" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd"> <!--引入数据源,替代mybatis中的数据源--> <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?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!--sqlSessionFactory创建--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--加载数据源--> <property name="dataSource" ref="dataSource"/> <!--装配mybatis的配置文件,spring可以完全取代mybatis的配置--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!--加载mapper的配置文件--> <property name="mapperLocations" value="classpath:com/ting/mapper/*.xml"/> </bean> <!--配置声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--结合sprin的aop织入--> <!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--给方法配置事务--> <!--配置事务的传播特性:propagation,默认是"REQUIRED",一般使用默认值就行,代表存在事务的时候使用,不存在事务时创建事务--> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="select*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置aop切入事务--> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.ting.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>
<!--sqlSessionFactory创建-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--加载数据源-->
<property name="dataSource" ref="dataSource"/>
<!--装配mybatis的配置文件,spring可以完全取代mybatis的配置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--加载mapper的配置文件-->
<property name="mapperLocations" value="classpath:com/ting/mapper/*.xml"/>
</bean>
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--结合sprin的aop织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给方法配置事务-->
<!--配置事务的传播特性:propagation,默认是"REQUIRED",一般使用默认值就行,代表存在事务的时候使用,不存在事务时创建事务-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="select*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置aop切入事务-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.ting.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
```