了解Spring
官网:https://spring.io/projects/spring-framework#learn
官方下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring
GitHub:https://github.com/spring-projects/spring-framework
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.15</version>
</dependency>
优点
Spring是一个开源的免费的框架(容器)
Spring是一个轻量级的、非入侵式的框架
控制反转(IOC),面向切面编程(AOP)
支持事务的处理,对框架整合的支持
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
组成
IOC创建对象的方式
在配置文件加载的时候,容器中管理的对象就已经初始化了
默认使用无参构造创建对象
使用有参构造创建对象的方法
-
下标赋值
<bean id="user" class="com.lzj.entity.User"> <constructor-arg index="0" value="lzj"></constructor-arg> </bean>
-
类型赋值
<bean id="user" class="com.lzj.entity.User"> <constructor-arg type="java.lang.String" value="lzj"></constructor-arg> </bean>
-
通过参数名
<bean id="user" class="com.lzj.entity.User"> <constructor-arg name="name" value="lzj"></constructor-arg> </bean>
Spring配置
-
别名
<!--别名,如果添加了别名,我们也可以使用别名获取到这个对象--> <alias name="user" alias="userNew"></alias>
-
Bean的配置
<!-- id:bean的唯一标识符,也就是相当于我们学的对象名 class:bean对象所对应的全限定名 :包名+类型 name:也是别名,而且name,可以同时取多个别名 --> <bean id="userT" class="com.lzj.entity.UserT" name="u1,u2"> <property name="name" value="lzj"></property> </bean>
-
import
一般用于团队开发,可以将多个配置文件导入合并为一个
假设,现在项目中有多个人开发,这3个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的baens.xml合并为一个总的
- applicationContext.xml
<import resource="beans.xml"></import> <import resource="beans2.xml"></import> <import resource="beans3.xml"></import>
使用的时候直接使用总的配置就可以了
依赖注入
Set方式注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性由容器来注入
【环境搭建】
-
复杂类型
public class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Address{" + "address='" + address + '\'' + '}'; } }
-
真实测试对象
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;
-
完善注入信息(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"> <bean id="address" class="com.lzj.entity.Address"> <property name="address" value="武汉"></property> </bean> <bean id="student" class="com.lzj.entity.Student"> <!-- 第一种,普通值注入,value--> <property name="name" value="lzj"></property> <!-- 第二种,Bean注入,ref--> <property name="address" ref="address"></property> <!-- 数组--> <property name="books"> <array> <value>红楼梦</value> <value>西游记</value> <value>水浒传</value> <value>三国演义</value> </array> </property> <!-- List--> <property name="hobbies"> <list> <value>听歌</value> <value>敲代码</value> <value>看电影</value> </list> </property> <!-- Map --> <property name="card"> <map> <entry key="身份证" value="2132132465456"></entry> <entry key="银行卡" value="546565432134"></entry> </map> </property> <!-- Set--> <property name="games"> <set> <value>LOL</value> <value>COC</value> <value>BOB</value> </set> </property> <!-- null--> <property name="wife"> <null></null> </property> <!-- properties--> <property name="info"> <props> <prop key="学号">20191025302</prop> <prop key="性别">男</prop> <prop key="姓名">lzj</prop> </props> </property> </bean> </beans>
-
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("student"); System.out.println(student); } }
p命名空间和c命名空间注入
p命名和c命名空间不能直接使用,需要导入xml约束
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
官方文档位置:
使用:
实体类:
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.lzj.entity.User" p:name="lzj" p:age="20"></bean>
<!-- c命名空间注入,通过构造器注入:construct-args-->
<bean id="user2" class="com.lzj.entity.User" c:name="lzj" c:age="20"></bean>
</beans>
测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
}
bean的作用域
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext . |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext . |
-
单例模式(Spring默认机制)
scope=“singleton”
<bean id="user2" class="com.lzj.entity.User" c:name="lzj" c:age="20" scope="singleton"></bean>
-
原型模式:每次从容器中get的时候,都会产生一个新对象
scope=“prototype”
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
-
其余的request、session、application、这些个只能在web开发中使用
Bean的自动装配
- 自动装配是Spring满足bean依赖一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
byName自动装配
需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
<bean id="cat" class="com.lzj.entity.Cat"></bean>
<bean id="dog" class="com.lzj.entity.Dog"></bean>
<!--
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid
-->
<bean id="people" class="com.lzj.entity.People" autowire="baName">
<property name="name" value="lzj"></property>
</bean>
byType自动装配
需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
<bean id="cat" class="com.lzj.entity.Cat"></bean>
<bean id="dog2" class="com.lzj.entity.Dog"></bean>
<!--
byName:会自动在容器上下文中查找,和自己对象属性类型相同的bean
-->
<bean id="people" class="com.lzj.entity.People" autowire="byType">
<property name="name" value="lzj"></property>
</bean>
使用注解实现自动装配
-
导入约束(context约束)
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd <context:annotation-config/>
-
配置注解的支持: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
直接在属性上使用即可!也可以在set方式上使用
使用Autowired我们可以不用编写Set方法了,前提是这个自动中装配的属性在IOC(Spring)容器中存在,且符合名字byType
如果@Autowired自动装配的环境比较复杂,自动装配无法通过-个注解【@Autowired】 完成的时候、我们可以使用@Qualifier(value=“xx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
public class People {
@Autowired
private Cat cat;
@Autowired
@Qualifier(value = "dog222")
private Dog dog;
private String name;
}
@Resource注解
-
导入相关依赖
<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api --> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
-
实体类中使用注解
public class People { @Resource private Cat cat; @Resource(name = "dog22") private Dog dog; private String name; }
区别
@Resource和@ Autowired的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @ Autowired通过byType的方式实现,若使用byType方式找不到则会使用@Qualifier注解按照byName方式,必须要求这个对象存在
- @Resource 默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!
- 执行顺序不同
使用注解进行开发
-
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: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.lzj.entity"></context:component-scan> <context:annotation-config/> </beans>
-
实体类使用注解(@Component)
//等价于<bean id="user" class="com.lzj.entity.User"/> //@Component组件 @Component public class User { public String name; }
-
-
属性如何注入
public class User { //相当于<property name="name" value="lzj"/> @Value("lzj") public String name; }
-
衍生的注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
-
dao [@Repository]
-
service [@Service]
-
controller [ @Controller ]
这四个注解功能都是一-样的, 都是代表将某个类注册到Spring中,装配Bean
-
-
自动装配置
-
@Autowired :自动装配通过类型。名字
如果Autowired不能唯一自动装配 上属性,则需要通过**@qualifier**(va1ue=“xxx”)
-
@Nullable 字段标记了这个注解,说明这个字段可以为null;
-
@Resource:自动装配通过名字。类型。
-
-
作用域(@Scope)
//指定作用域为原型模式 @Scope("prototype") public class User { public String name; }
-
小结
xml与注解:
- xml更加万能,适用于任何场合!维护简单方便
- 注解不是自己类使用不了,维护相对复杂!
xml与注解最佳实践:
-
xml用来管理bean;
-
注解只负责完成属性的注入;
-
我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
<!-- 指定要扫描的包,这个包下的注解就会生效--> <context:component-scan base-package="com.lzj"></context:component-scan> <context:annotation-config/>
使用Java的方式配置Spring
实体类
@Component
public class User {
@Value(value = "lzj")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置文件
@Configuration
@ComponentScan("com.lzj.entity")//默认会扫描该类所在的包下所有的配置类
@Import(LzjConfig2.class)
public class LzjConfig {
//注册-个bean ,就相当 于我们之前写的一-个bean 标签
//这个方法的名字,就相当Fbean标签中的id属性
//这个方法的返回值,就相当Fbean标签中的cLass属性
@Bean
public User getUser(){
return new User();//就是返回要注入到bean的对象
}
}
测试类
public class MyTest {
public static void main(String[] args) {
//.如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig. 上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(LzjConfig.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}
代理模式
静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
代码步骤:
-
接口
//租房 public interface Rent { public void rent(); }
-
真实角色
//房东 public class Host implements Rent{ @Override public void rent() { System.out.println("房东要租房出去"); } }
-
代理角色
//中介 public class Proxy { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void rent(){ host.rent(); } }
-
客户端访问代理角色
//要租房的人 public class Client { public static void main(String[] args) { Host host = new Host(); Proxy proxy = new Proxy(host); proxy.rent(); } }
动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理、基于类的动态代理
- 基于接口----JDK动态代理
- 基于类-------cglib
- java字节码实现:javsist
代码步骤:
-
接口
//租房 public interface Rent { public void rent(); }
-
真实角色
//房东 public class Host implements Rent{ @Override public void rent() { System.out.println("房东要租房出去"); } }
-
创造一个类自动生成代理类
//这个类的方式可以通用 public class ProxyInvocationHandler implements InvocationHandler { //被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } //生成得到代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //处理代理实例,并返回结果,method是已经通过反射获取的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target, args); return result; } }
-
客户端访问代理角色
//要租房的人 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(); } }
Spring中的AOP
AOP在Spring中的作用
提供声明式事务,允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
- 切面(ASPECT) :横切关注点被模块化的特殊对象。即,它是-一个类。
- 通知(Advice) :切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target) :被通知对象。
- 代理(Proxy) :向目标对象应用通知之后创建的对象。
- 切入点(PointCut) :切面通知执行的“地点”的定义。
- 连接点(jointPoint) :与切入点匹配的执行点。
使用Spring的API实现Aop
代码步骤:
-
导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
-
接口
public interface UserService { public void add(); public void delete(); public void update(); public void select(); }
-
实现类
public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("更新了一个用户"); } @Override public void select() { System.out.println("查询了一个用户"); } }
-
前置日志
public class Log implements MethodBeforeAdvice { //method:要执行的目标对象的方法 //args:参数 //target:目标对象 @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了"); } }
-
后置日志
public class AfterLog implements AfterReturningAdvice { //returnValue:返回值 @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了"+method.getName()+"返回的结果为:"+returnValue); } }
-
xml配置
需要在前面导入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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 注册bean--> <bean id="userservice" class="com.lzj.service.UserServiceImpl"></bean> <bean id="log" class="com.lzj.log.Log"></bean> <bean id="afterlog" class="com.lzj.log.AfterLog"></bean> <!--配置aop:需要导入aop的约束--> <aop:config> <!-- 切入点:expression;表达式,execution(要执行的位置! * * * * *)--> <aop:pointcut id="pointcut" expression="execution(* com.lzj.service.UserServiceImpl.*(..))"/> <!-- 执行环绕增加--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor> <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"></aop:advisor> </aop:config> </beans>
-
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理代理的是接口 UserService userservice = (UserService) context.getBean("userservice"); userservice.add(); } }
自定义实现AOP
相比于使用Spring的API实现Aop修改了xml配置文件和将前置日志和后置日志替换成了自定义类
代码步骤:
-
导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
-
接口
public interface UserService { public void add(); public void delete(); public void update(); public void select(); }
-
实现类
public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("更新了一个用户"); } @Override public void select() { System.out.println("查询了一个用户"); } }
-
自定义类
public class DiyPointCut { public void before(){ System.out.println("=========方法执行前========="); } public void after(){ System.out.println("=========方法执行后========="); } }
-
xml配置
需要在前面导入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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 注册bean--> <bean id="userservice" class="com.lzj.service.UserServiceImpl"></bean> <bean id="log" class="com.lzj.log.Log"></bean> <bean id="afterlog" class="com.lzj.log.AfterLog"></bean> <!-- 方式二:自定义类--> <bean id="diy" class="com.lzj.diy.DiyPointCut"></bean> <aop:config> <!-- 自定义切面,ref 要引用的类--> <aop:aspect ref="diy"> <!-- 切入点--> <aop:pointcut id="pointcut" expression="execution(* com.lzj.service.UserServiceImpl.*(..))"/> <!-- 通知--> <aop:before method="before" pointcut-ref="pointcut"/> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans>
-
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理代理的是接口 UserService userservice = (UserService) context.getBean("userservice"); userservice.add(); } }
使用注解实现AOP
相比于使用自定义类AOP,修改了自定义类和xml配置文件
代码步骤:
-
导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
-
接口
public interface UserService { public void add(); public void delete(); public void update(); public void select(); }
-
实现类
public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("更新了一个用户"); } @Override public void select() { System.out.println("查询了一个用户"); } }
-
自定义类
//使用注解方式实现AOP @Aspect public class AnnotationPointCut { @Before("execution(* com.lzj.service.UserServiceImpl.*(..))") public void before(){ System.out.println("=========方法执行前========="); } @After("execution(* com.lzj.service.UserServiceImpl.*(..))") public void after(){ System.out.println("=========方法执行后========="); } //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点 @Around("execution(* com.lzj.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("环绕后"); } }
-
xml配置
需要在前面导入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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 注册bean--> <bean id="userservice" class="com.lzj.service.UserServiceImpl"></bean> <bean id="log" class="com.lzj.log.Log"></bean> <bean id="afterlog" class="com.lzj.log.AfterLog"></bean> <!-- 方法三:使用注解实现AOP--> <bean id="annotation" class="com.lzj.diy.AnnotationPointCut"/> <!-- 开启注解支持--> <aop:aspectj-autoproxy/> </beans>
-
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理代理的是接口 UserService userservice = (UserService) context.getBean("userservice"); userservice.add(); } }
aspect和advice的区别
< aop:aspect>定义切面时,只需要定义一般的bean就行,而定义< aop:advisor>中引用的通知时,通知必须实现Advice接口
< aop:advisor>和< aop:aspect>其实都是将通知和切面进行了封装,原理基本上是一样的,只是使用的方式不同而已
- < aop:aspect>:定义切面(切面包括通知和切点)
- < aop:aspect>大多用于日志,缓存
- < aop:advisor>:定义通知器(通知器跟切面一样,也包括通知和切点)
- < aop:advisor>大多用于事务管理
整合Mybatis
步骤:
-
导入相关jar包
-
junit
-
mybatis
-
mysql数据库
-
spring相关
-
aop置入
-
mybatis-spring【new】: https://mybatis.org/spring/zh/index.html
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.15</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.15</version> </dependency> <!-- 使用Spring的API实现Aop--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency> <!-- 整合mybatis和spring--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> </dependencies> <!--在build中配置resources,来防止我们资源导出失败的问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
编写配置文件
-
测试
整合方式一
采用SqlSessionTemplate
-
编写mybatis-config.xml
<?xml version="1.0" encoding="UTF8" ?> <!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"/> <!-- 开启缓存--> <setting name="cacheEnabled" value="true"/> <!-- <setting name="logImpl" value="LOG4J"/>--> <!-- 开启驼峰映射--> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!-- 别名--> <typeAliases> <package name="com.lzj.entity"/> </typeAliases> </configuration>
-
编写spring-dao.xml配置文件
编写数据源配置、sqlSessionFactory、sqlISessionTemplate
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"> <!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid 我们这里使用Spring提供的JDBC:org.springframework.jdbc.datasource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/> <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配置文件--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/lzj/dao/*.xml"/> </bean> <!-- SqlSessionTemplate:就是我们使用的sqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!-- 只能使用构造器注入sqlSessionFactor,因为它没有set方法--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> </beans>
-
需要给接口加实现类[]
接口
public interface UserMapper { public List<User> queryUser(); }
UserMapper.xml配置文件
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace=绑定一个对应的Dao/Mapper接口--> <mapper namespace="com.lzj.dao.UserMapper"> <!-- select查询--> <!-- id对应接口方法的名字--> <select id="queryUser" resultType="user"> select * from mybatis.user </select> </mapper>
实现类
public class UserMapperImpl implements UserMapper{ //我们所有操作,都使用sqlSession来执行,现在都使用SqlSessionTemplate private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } @Override public List<User> queryUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.queryUser(); } }
-
将自己写的实现类,注入到Spring中,将编写spring-dao.xml配置文件引入到Spring的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"></import> <bean id="userMapper" class="com.lzj.dao.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>
-
测试使用即可!|
@Test public void queryUserTest2(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); List<User> users = userMapper.queryUser(); for (User user : users) { System.out.println(user); } }
整合方式二
采用继承SqlSessionDaoSupport类
可删除掉spring-dao.xml配置文件中的SqlSessionTemplate
-
实现接口类
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{ @Override public List<User> queryUser() { return getSqlSession().getMapper(UserMapper.class).queryUser(); } }
-
xml中注册接口类
<bean id="userMapper2" class="com.lzj.dao.UserMapperImpl2"> <property name="sqlSessionFactory" ref="sqlSessionFactory"></property> </bean>
-
测试
@Test public void queryUserTest3(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper2", UserMapper.class); List<User> users = userMapper.queryUser(); for (User user : users) { System.out.println(user); } }
spring中的事务管理
事务ACID原则:
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作同一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!
声明式事务
AOP
在spring-dao中增加以下配置
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!-- 结合AOP实现事务的置入-->
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<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="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入点-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.lzj.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
编程式事务
需要在代码中进行事务的管理
为什么需要事务
- 如果不配置事务,可能存在数据提交不一致的情况下;
- 如果我们不在SPRING中去配置声明式事务,我们就需要在代码中手动配置事务!
- 事务在项目的开发中十分重要, 涉及到数据的一致性和完整性问题,不容马虎!
serMapper.class);
List users = userMapper.queryUser();
for (User user : users) {
System.out.println(user);
}
}
spring中的事务管理
事务ACID原则:
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作同一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!
声明式事务
AOP
在spring-dao中增加以下配置
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!-- 结合AOP实现事务的置入-->
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<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="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入点-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.lzj.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
编程式事务
需要在代码中进行事务的管理
为什么需要事务
- 如果不配置事务,可能存在数据提交不一致的情况下;
- 如果我们不在SPRING中去配置声明式事务,我们就需要在代码中手动配置事务!
- 事务在项目的开发中十分重要, 涉及到数据的一致性和完整性问题,不容马虎!