一、Spring简介
1.什么是Spring
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
?Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。
2.Spring组成

?Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。
二、搭建Spring环境
1.创建maven-java项目
1.1导入依赖
<dependencies>
<!-- spring-context依赖中关联了其他核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
</dependencies>
1.2Spring配置文件
<?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">
</beans>
1.入门演示-IOC
1.1IOC介绍
IOC: Inversion of control 控制反转,以前对象创建的控制权在自己,现在将控制权交给Spring,由Spring框架创建对象。
需求:有一接口UserService,有一实现类UserServiceImpl.使用接口直接调用方法让其执行.
1.1详细步骤
1.UserService接口
public interface UserService {
void findUserById();
}
2.UserServiceImpl实现类实现接口UserService
public class UserServiceImpl implements UserService {
@Override
public void findUserById() {
System.out.println("UserServiceImpl.findUserById()执行" );
}
}
3.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">
<!-- spring配置文件applicationContext.xml相当于是
一个容器,在这里配置整个项目中所需要的对象
-->
<!-- 一个bean标签代表一个类,会创建该类对象
class 是要交给Spring创建对象的类路径
id 是创建完成后的对象名
-->
<bean id="userService" class="com.qf.service.impl.UserServiceImpl"/>
</beans>
4.测试类
public class TsetIOC {
@Test
public void test(){
String path = "applicationContext.xml";
// 根据配置文件创建出spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);
// 从容器中取出对象(根据对象名获得对象,配置文件中的id)
UserService userService = (UserService) context.getBean("userService");
userService.findUserById();
}
}
三、DI-依赖注入
依赖注入就是属性赋值。
1.入门演示-DI
需求:给UserServiceImpl类中的UserDao属性赋值
1.实现类UserServiceImpl实现UserService,并创建Dao对象,给属性提供set方法
public class UserServiceImpl implements UserService {
// 创建Dao对象
private UserDao userDao;
// 给属性提供set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void findUserById() {
System.out.println("UserServiceImpl.findUserById()执行" );
userDao.findUserById();
}
}
2.创建一个接口UserDao
public interface UserDao {
void findUserById();
}
3.实现类UserDaoImpl实现接口UserDao
public class UserDaoImpl implements UserDao {
@Override
public void findUserById() {
System.out.println("UserDaoImpl.findUserById");
}
}
4.applicationContext.xml配置文件
<bean id="userService" class="com.qf.service.impl.UserServiceImpl">
<!-- 给属性赋值(DI)
1) 属性要有set方法
2) 属性值是另一个类对象,所以需要使用ref引用另一个类的对象id
-->
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 创建一个UserDao对象 -->
<bean id="userDao" class="com.qf.dao.impl.UserDaoImpl"/>
5.测试类
@Test
public void test(){
String path = "applicationContext.xml";
// 根据配置文件创建出spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);
// 从容器中取出对象(根据对象名获得对象)
UserService userService = (UserService) context.getBean("userService");
userService.findUserById();
}
总结:依赖注入就是给属性赋值,Spring提供了两种方案,一种set方式赋值,另一种是构造方法赋值。
2.依赖注入-基本类型
1.创建实体类
public class User {
private int id;
private String username;
private Date birthday;
private double score;
// set get...
}
2.applicationContext.xml配置文件
<bean id="user" class="com.qf.model.User">
<!--
一个property标签给一个属性赋值
name 是类的属性名 value是属性值
-->
<property name="id" value="18"/>
<property name="username" value="admin"/>
<property name="score" value="99.9"/>
<!-- 日期这里使用value赋值,且格式只能是yyyy/MM/dd格式 -->
<property name="birthday" value="2000/01/01"/>
</bean>
测试类:
@Test
public void test2(){
String path = "applicationContext.xml";
// 根据配置文件创建出spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);
// 从容器中取出对象(根据对象名获得对象)
User user = (User) context.getBean("user");
System.out.println(user );
}
3.依赖注入-容器
数组、List、Set、Map
1.创建实体类
public class User{
// 容器类型
private String[] phones;
private List<String> list;
private Set<String> set;
private Map<String,Integer> map;
// set get
}
2.applicationContext.xml配置文件
<bean id="user" class="com.qf.model.User">
<!-- 数组 -->
<property name="phones">
<array>
<value>110</value>
<value>120</value>
<value>119</value>
</array>
</property>
<!-- List,会允许重复 -->
<property name="list">
<list>
<value>奔驰</value>
<value>奔驰</value>
<value>宝马</value>
<value>奥迪</value>
</list>
</property>
<property name="set">
<!-- Set,不允许重复 -->
<set>
<value>145平</value>
<value>145平</value>
<value>155平</value>
<value>165平</value>
</set>
</property>
<!--Map-->
<property name="map">
<map>
<entry key="一" value="1"/>
<entry key="二" value="2"/>
<entry key="三" value="3"/>
</map>
</property>
</bean>
3.测试类
@Test
public void test2(){
String path = "applicationContext.xml";
// 根据配置文件创建出spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);
// 从容器中取出对象(根据对象名获得对象)
User user = (User) context.getBean("user");
System.out.println(user );
}
4.自动注入
applicationContext.xml配置文件
<!--
autowire 属性,spring会在自动给UseServiceImpl类中的属性赋值
自动注入的方式:
byName: 通过名字注入
是属性名跟当前容器中bean标签id一致,既可以自动注入
byTyoe: 通过类型注入
需要给中属性赋值,会在当前容器根据类型找到后,自动赋值
与对象名无关.如果当前容器中有多个该类型的值,会赋值失败
-->
<bean id="userService" class="com.qf.service.impl.UserServiceImpl" autowire="byType"/>
<bean id="userDao1" class="com.qf.dao.impl.UserDaoImpl"/>
????????总结
????????自动注入的两种方式:
- byName: 通过属性名和容器中对象名一致,即可自动注入
- byType: 属性类型和容器中对象的类型一致,即可自动注入
四、注解实现IOC-DI
上面我们都是使用xml配置实现IOC和DI,以后将使用注解实现IOC和DI,即XML中不再配置很多标签了。
1.常用注解
注解 | 作用 | 被替代标签 | 位置 |
---|
@Component | 创建对象 | <bean> | 类上 | @Controller | 创建对象 | <bean> | 控制层的类上 | @Service | 创建对象 | <bean> | 业务层的类上 | @Repository | 创建对象 | <bean> | 持久层的类上 | @Value | 给基本类型属性赋值 | <property> | 属性上 | @Autowired | 给引用类型属性赋值 | autowired的属性 | 属性上 |
注意:@Component、@Controller、@Service、@Repository都是用来创建对象,只不过建议是在相应的位置使用相应的注解。
2.注解使用演示1(注解赋值)
需求:Teacher类,使用注解来创建Teacher类对象,以及给对象属性赋值。
1.创建Teacher实体类
package com.qf.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component // 取代<bean>,默认对象名就是类名小写
public class Teacher {
@Value("20") // 取代<property>
private int age;
@Value("老王")
private String name;
@Value("2020/01/01")
private Date birthday;
// set get toString
}
2.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--
开启注解扫描,即让注解生效
-->
<context:component-scan base-package="com.qf"/>
</beans>
3.测试类
@Test
public void test5(){
String path = "applicationContext3.xml";
// 根据配置文件创建出spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);
// 从容器中取出对象(默认是类名小写)
Teacher teacher = (Teacher) context.getBean("teacher2");;
System.out.println(teacher );
}
3注解使用演示2(Service注入Dao)
需求:UserServiceImpl注入UserDao属性。
1.UserDaoImpl实现UserDao接口
@Repository // 创建对象,取代<bean>
public class UserDaoImpl implements UserDao {
@Override
public void findUserById() {
System.out.println("UserDaoImpl.findUserById");
}
}
2.UserServiceImpl实现UserService接口
@Service // 创建对象,取代<bean>
public class UserServiceImpl implements UserService {
@Autowired // 自动注入,按照类型注入byType
private UserDao userDao;
@Override
public void findUserById() {
System.out.println("UserServiceImpl.findUserById()执行" );
userDao.findUserById();
}
}
3.applicationContext.xml开启注解
<!-- 开启注解扫描,即让注解生效 -->
<context:component-scan base-package="com.qf"/>
按类型注入多个同类型,注入失败怎么解决
@Service
public class UserServiceImpl implements UserService {
// 创建Dao对象
@Autowired // 自动注入,按照类型注入
// 当同类型的对象有多个时,无法自动注入,需要手动指定注入哪个对象
// 使用@Qualifier指定注入的对象名
@Qualifier("userDaoImpl2")
private UserDao userDao;
// ...
}
五、代理模式
1.代理介绍
简介:
代理就是一个中介,不仅仅可以实现某种目的还可以加上额外的操作的方式。
作用:
实现对目标对象原有的功能增强,即扩展目标对象的功能方法,并且不会修改原有代码。
分类:
- ?静态代理,在运行前,通过编写代码的方式生成代理类
- ?动态代理,在运行后,通过反射机制生成代理类
2.静态代理
静态代理就是:一个代理只能做一件事.做其他事情,需要再创建新代理.。
1)代理者和被代理者都实现相同的接口
2)代理者包含被代理者的对象
3)创建代理对象时传入被代理对象
4)代理者执行方法时,会调用被代理者的方法,同时扩展新的功能
2.1静态代理实例
需求:实现房东租房
1.创建接口
public interface FangDong {
void zufang();
}
2.被代理者实现接口
public class FangdongImpl implements FangDong {
@Override
public void zufang() {
System.out.println("房东租房..." );
}
}
3.代理者实现接口
public class FangdongProxy {
// 目标对象
private FangDong fangDong;
public FangdongProxy(FangDong fangDong){
this.fangDong = fangDong;
}
void zufang(){
// 前置增强
System.out.println("前:发传单,找客源" );
// 房东租房
fangDong.zufang();
// 后置增强
System.out.println("后:签合同" );
}
}
4.测试
public static void main(String[] args) {// 开始租房
// 找代理
FangdongProxy proxy = new FangdongProxy(new FangdongImpl( ));
// 真正租房
proxy.zufang();
}
3.动态代理
动态代理会动态的为目标类产生代理对象.动态代理有两种实现方案:
- JDK动态代理,只能代理接口.即目标类要有接口
- CGLIB动态代理,可以代理接口,也可以代理类,目录类可以有接口,也可以没有接口
3.1JDK动态代理
JDK代理,是Java自有技术无需导包
需求:使用动态代理技术,动态的产生房东代理对象,汽车厂商的代理
1.JDK代理实现InvocationHandler接口
public class JDKProxy implements InvocationHandler {
// 目标类
private Object target;
// 指定目标对象
public JDKProxy(Object target){
this.target = target;
}
/**
* @param proxy 被代理对象
* @param method 目标方法
* @param args 目标方法的参数
* @return 目标方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 目标方法前:
System.out.println("前置增强" );
// 目标方法执行
Object obj = method.invoke(target,args);
System.out.println("后置增强" );
return obj;
}
}
2.测试
public static void main(String[] args) {
// 目标类的类加载器
ClassLoader classLoader = FangdongImpl.class.getClassLoader( );
// 目标类的实现的所有接口
Class<?>[] interfaces = FangdongImpl.class.getInterfaces( );
// 目标方法执行处理器
JDKProxy handler = new JDKProxy(new FangdongImpl( ));
/**
* 参数1: 目标类的类加载器
* 参数2: 目标类的所实现的所有接口
* 参数3: 自己实现的目标方法处理器
*/
FangDong fangDong = (FangDong) Proxy.newProxyInstance(classLoader, interfaces, handler);
fangDong.zufang();
}
总结:动态代理,会动态产生目标类的代理对象,JDK的动态代理,目标必须有接口。
3.2CGLIB动态代理
CGLIB动态代理技术,又叫字节码增强.动态产生代理对象,可以代理接口也可以代理实现类.CGLIB是第三方技术,spring框架中已经整合了cglib的技术,所以只需导入spring-aop的依赖即可。
需求:使用动态代理技术,动态的产生房东代理对象,汽车厂商的代理
1.CGLIB代理实现MethodInterceptor接口
public class MyCglibInterceptor implements MethodInterceptor {
// cglib的增强器
private Enhancer enhancer = new Enhancer();
// 创建拦截器时,指定目标类的字节码
public MyCglibInterceptor(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
}
// 提供一个获得代理对象的方法
public Object createProxyBean(){
return enhancer.create();
}
/**
* @param target 目标对象
* @param method
* @param args 目标方法的参数
* @param methodProxy 目标方法的代理对象
* @return 目标方法的返回值
* @throws Throwable
*/
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 目标方法前:
System.out.println("前置增强:权限校验,或者事务开启" );
// 目标方法执行
Object ret = methodProxy.invokeSuper(target,args);
// 目标方法前:
System.out.println("后置增强:日志记录,或者事务提交" );
return ret;
}
}
2.测试
public static void main(String[] args) {
// 此处,只需要将其他类字节码文件传入此处
// 即可得到其他类的代理对象
MyCglibInterceptor interceptor = new MyCglibInterceptor(CarFactoryImpl.class);
CarFactoryImpl carFactory = (CarFactoryImpl) interceptor.createProxyBean( );
carFactory.saleCar();
}
总结:CGLIB动态代理,会动态的给类产生代理对象,目标类可以没有接口,也可以有接口,都可以代理。
3.3总结
代理的目的: 将目标方法功能增强.
代理的方式: 静态代理和动态代理
什么区别:
- 静态代理: 每个类都需要自己创建代理对象,一个代理只能代理一个类
- 动态代理: 给每个类动态产生代理对象.(按需产生)
动态代理如何实现:
- jdk的动态代理: jdk动态代理只能代理接口(目标类必须有接口)
- cglib的动态代理:可以代理接口,也可以代理类(目标类可以有接口,也可以没接口)
六、AOP编程
1.AOP介绍
aop:aspect oriented programming(面向切面编程),它是对一类对象或所有对象编程。
? ? ? ? 核心:在不增加代码的基础上,还增加新功能
理解:
面向切面:其实就是,把一些公共的“东西”拿出来,比如说,事务,安全,日志,这些方面,如果你用的到,你就引入。
面向切面编程的作用:
将项目中与核心逻辑无关的代码横向抽取成切面类,通过织入作用到目标方法,以使目标方法执行前后达到增强的效果。
优点:
- 可以对业务逻辑的各个部分进行隔离
- 抽取代码,复用,提供效率
- 减少耦合
- 利于代码扩展
AOP术语:
- 目标类(Target): 被代理的类
- 连接点(JoinPoint): 目标类中准备被切入的方法
- 切入点(Pointcut): 真正执行的目标方法
- 切面(Aspect) : 切面中定义中增强的方法
- 增强(Advice): 也叫通知,就是在目标方法执行前/后的方法
- 织入(Weaving): 将增强作用到切入点的过程
2.AOP分类
5中通知的分类:
-
前置通知(Before Advice):在目标方法被调用前调用通知功能,场景:一般用来做权限校验 -
后置通知(After Advice):在目标方法被调用之后调用通知功能,场景: 释放资源,或者记录日志 -
返回通知(After-returning):在目标方法成功执行之后调用通知功能,场景:数据库事务 -
异常通知(After-throwing):在目标方法抛出异常之后调用通知功能,场景:得到目标方法返回值再处理 -
环绕通知(Around):把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能。? 场景:可以获得目标方法的异常信息,用于记录日志,或者进行异常拦截
3.入门演示(步骤)
1.加入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
2.创建接口
public interface UserService {
void queryAllAdmin();
void addAdmin();
}
3.创建实现类
public class UserServiceImpl implements UserService{
@Override
public void queryAllAdmin() {
System.out.println("UserServiceImpl中queryAllAdmin执行了");
}
@Override
public void addAdmin() {
System.out.println("UserServiceImpl中addAdmin执行了");
}
}
4.创建切面类
public class MyAspect {
/**
* 环绕通知
* @param joinPoint
*/
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//目标方法前
System.out.println("前置增强:开启事务");
//目标方法执行
Object proceed = joinPoint.proceed();
//目标方法执行后
System.out.println("后置增强:提交事务");
return proceed;
}
/**
* 前置通知
* @param joinPoint
*/
public void befor(JoinPoint joinPoint){
Object target = joinPoint.getTarget();
System.out.println("前置增强,获得目标类对象:"+target);
Signature signature = joinPoint.getSignature();
System.out.println("前置增强,获得目标方法:"+signature);
String name = signature.getName();
System.out.println("前置增强,获得目标方法名字:"+name);
System.out.println("前置增强:权限校验");
}
/**
* 后置通知
* @param joinPoint
*/
public void after(JoinPoint joinPoint){
//应用场景:还可以做一些关流,释放资源的动作
System.out.println("后置通知:记录执行的日志");
}
/**
* 环绕通知1
* @param joinPoint:目标方法
* @return
*/
public Object around1(ProceedingJoinPoint joinPoint) throws Throwable {
//目标执行前
System.out.println("环绕-前置增强:开启事务");
//目标执行
Object proceed = joinPoint.proceed();
//目标执行后
System.out.println("环绕-后置增强:提交事务");
return proceed;
}
/**
* 后置返回通知
* @param ret1:返回的参数
* @return
*/
public Object afterReturn(Object ret1){
System.out.println("后置返回通知:"+ret1);
return ret1;
}
/**
* 异常处理通知
* @param e
*/
public void MyThrow(Exception e){
//可以做全局异常处理,记录异常信息到日志
System.out.println("异常通知,获得异常信息"+e.getMessage());
}
}
4.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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--创建目标类-->
<bean id="userService" class="com.ymk.service.UserServiceImpl"/>
<!--创建切面类对象-->
<bean id="myAspect" class="com.ymk.aspect.MyAspect"/>
<!--织入-->
<aop:config>
<!--抽取出来,方便后边调用-->
<aop:pointcut id="p1" expression="execution(* com.ymk.service.*.*(..))"/>
<!--配置切面,引用自定义切面对象-->
<aop:aspect ref="myAspect">
<!--配置环绕通知-->
<aop:around method="around" pointcut-ref="p1"/>
<!--配置前置通知-->
<aop:before method="befor" pointcut-ref="p1"/>
<!--配置后置通知-->
<aop:after method="after" pointcut-ref="p1"/>
<!--配置环绕通知-->
<aop:around method="around1" pointcut-ref="p1"/>
<!--配置后置返回通知
returning指定增强方法的参数名ret
-->
<aop:after-returning method="afterReturn" pointcut-ref="p1" returning="ret1"/>
<!--配置异常通知
throwing指定增强方法的参数名
-->
<aop:after-throwing method="MyThrow" pointcut-ref="p1" throwing="e"/>
</aop:aspect>
</aop:config>
</beans>
4.AOP注解
4.1注解开发AOP
bean id="" class="目标类路径"——> @Service
bean id="切面对象" class="切面类路径" ——> @Component
aop:confing
aop:aspect ref="切面对象" ——> @Aspect
aop:before ——>@Before
aop:after ——>@After
aop:pointcut ——>@Pointcut
4.2AOP注解演示
1.创建接口
public interface UserService {
void findUserById();
}
2.UserServiceImpl实现接口UserService
@Service // 让spring创建对象,将该类交给Spring托管
public class UserServiceImpl implements UserService {
@Override
public void findUserById() {
System.out.println("com.qf.service.UserServiceImpl.findUserById()");
}
}
3.切面类
@Component//加注解不用写bean标签
@Aspect//声明这是个切面
public class MyAspect {
/**
* 将表达式抽取出来,方便复用
*/
@Pointcut("execution(* com.ymk.service.*.*(..))")
public void pointcut() {
}
/**
* 前置通知,其中写的是切入点表达式的方法名,注意不要忘了括号()
*/
//@Before注解里写表达式
@Before("pointcut()")
public void myBefore() {
System.out.println("前置增强:这是前置通知");
}
/**
* 后置通知
*/
@After("pointcut()")
public void myAfter(JoinPoint joinPoint) {
System.out.println("后置增强:这是后置增强" + joinPoint.getSignature().getName());
}
/**
* 环绕通知
*/
@Around("pointcut()")
public void myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("前置增强:开启事务");
Object proceed = joinPoint.proceed();
System.out.println("后置增强:提交事务");
}
}
4.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"
xmlns:context="http://www.springframework.org/schema/context"
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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描注解使其生效 -->
<context:component-scan base-package="com.qf"/>
<!-- 开启AOP的自动代理配置 -->
<aop:aspectj-autoproxy/>
</beans>
5.测试
public static void main(String[] args) {
// 获得容器对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器获得对象,对象名一定是类名首字母小写
UserService userService = context.getBean("userServiceImpl", UserService.class);
// 执行目标方法,目标方法前后都会执行增强方法
userService.findUserById();
}
七、MyBatis和Spring框架整合
1.演示
1.1加入依赖
<dependencies>
<!--—————————mysql架包—————————-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!--————————mybatis架包————————-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--————————log4j日志架包————————-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!--————————加入servlet依赖(servlet的jar)————————-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--———————jsp的依赖(jsp相关的jar加进来)————————-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!--——————注解@Test测试类架包——————-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--——————逆向工程架包——————-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<!--——————spring-context依赖中关联了其他核心依赖——————-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--——————spring和mybatis整合时,需要的架包——————-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--————————导入aop依赖————————-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--————————导入切面aspect依赖————————-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--——————spring事务—————-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.14.RELEASE</version>
</dependency>
<!--——————spring操作数据库JDBC——————-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.14.RELEASE</version>
</dependency>
<!--——————druid阿里的连接池——————-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!--——————分页插件—————-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
</dependencies>
1.2db.properties文件配置
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bank?useSSL=false
jdbc.username=root
jdbc.password=123456
# 配置初始化大小、最小、最大
jdbc.initialSize=5
jdbc.minIdle=3
jdbc.maxActive=20
#配置获取连接等待超时的时间
jdbc.maxWait=0
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
jdbc.timeBetweenEvictionRunsMillis=600000
#配置一个连接在池中最小生存的时间,单位是毫秒
jdbc.minEvictableIdleTimeMillis=300000
1.3mybatis-config.xml文件配置
<!-- 根标签 -->
<configuration>
<!-- 此处大部分的配置,都可以交给Spring处理 -->
<!--——————给类起别名,路径为包直接扫描包,不用每次配置——————-->
<typeAliases>
<package name="com.qf.model"/>
</typeAliases>
</configuration>
1.4applicationContext.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"
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/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--—————开启注解扫描,即让注解生效—————-->
<context:component-scan base-package="com.ymk"/>
<!--—————开启AOP自动代理配置—————-->
<aop:aspectj-autoproxy/>
<!--———————读取db.properties———————-->
<context:property-placeholder location="classpath:db.properties"/>
<!--—————1 druid数据源 实例化druid—————-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--—————配置初始化大小、最小、最大——————-->
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!--——————配置获取连接等待超时的时间———————-->
<property name="maxWait" value="${jdbc.maxWait}"/>
<!--——配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒——— -->
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<!--————配置一个连接在池中最小生存的时间,单位是毫秒————-->
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
<property name="testWhileIdle" value="true"/>
<!--————这里建议配置为TRUE,防止取到的连接不可用—————-->
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="false"/>
</bean>
<!--—————2 创建Mybatis的工厂对象——————-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--————————设置数据库连接池———————— -->
<property name="dataSource" ref="dataSource"/>
<!--—————加载mybatis主配置文件 classpath 表示classes目录所在路径—————-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--————————加载映射文件———————— -->
<property name="mapperLocations" value="classpath:com/ymk/mapper/*.xml"/>
</bean>
<!--—————SqlSessionFactoryBean具体加载那个接口,adminDao,讲接口代理对象实例化出来
spring就是依赖控制反转将对象创建出来的——————-->
<!--———————3设置Mybatis的映射接口 ———————-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--——设置映射接口所在包,会将mapper下所有的接口实例化出一个对象,不用sqlSession.getMapper了——-->
<property name="basePackage" value="com.ymk.mapper"></property>
</bean>
</beans>
1.5创建UserService接口和UserServiceImpl实现类
public interface UserService {
User findUserById(int id);
}
@Service
public class UserServiceImpl implements UserService {
// 设置Dao属性
@Autowired // 自动注入Mapper
private UserMapper userMapper;
@Override
public User findUserById(int id) {
User user = userMapper.findUserById(id);
return user;
}
}
1.6UserMapper.java和UserMapper.xml
public interface UserMapper {
User findUserById(int id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
1.7测试
public class TestSpringMybatis {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = context.getBean("userServiceImpl", UserService.class);
User user = service.findUserById(51);
System.out.println(user);
}
}
2.Spring整合Mybatis后Log4j不生效问题
解决方法:
将log4j依赖更新为log4j12依赖
<!--————————log4j日志架包————————-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
3.分页插件
分页插件作用: 可以自动完成分页功能。
以前需要自己在SQL中拼接limit语句,而且需要自己完成count()计算.
现在使用了分页插件,只需要正常查询全部数据,不用考虑关于分页的limit拼接问题,和count的数据条数等问题,插件全部搞定。
1.加入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
2.将分页插件的配置放在applicationContext.xml的SqlSessionFactory中
<!-- 设置分页插件 -->
<property name="plugins">
<set>
<!-- 创建分页插件对象,其实是一个拦截器 -->
<bean class="com.github.pagehelper.PageInterceptor">
<!-- 给对象指定属性 -->
<property name="properties">
<props>
<!-- 指定数据库类型 -->
<prop key="helperDialect">mysql</prop>
</props>
</property>
</bean>
</set>
</property>
3.创建UserService接口和UserServiceImpl实现类
public interface UserService {
List<User> findAll();
}
@Service
public class UserServiceImpl implements UserService {
// 设置Dao属性
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.findAll();
}
}
4.创建UserMapper.java
public interface UserMapper {
List<User> findAll();
}
5.创建UserMapper.xml
<select id="findAll" resultType="User">
select * from user
</select>
6.在代码中使用分页功能
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = context.getBean("userServiceImpl", UserService.class);
// 设置分页
PageHelper.startPage(2,2);
// 查询全部
List<User> all = service.findAll( );
for (User user : all) {
System.out.println(user );
}
// 将查询返回的集合,交给分页插件,返回给所有分页数据
PageInfo<User> pageInfo = new PageInfo<>(all);
System.out.println(pageInfo );
}
底层原理:
拦截Mybatis发出SQL语句,自动拼接Limit 语句,完成分页语句.另外还会发出SELECT count(0) FROM user 计算数据条数。
|