IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring笔记 -> 正文阅读

[Java知识库]Spring笔记

Spring

核心思想

【IOC(控制反转)】

【IOC(Inversion of control 控制反转)】

定义

? 将对象的创建由原来的new转移到配置文件中,交给spring工厂来处理创建对象

<bean id="aa" class="com.zx.UserDaoImpl"></bean>

【DI(Dependency Injection 依赖注入)】

定义

? Spring不仅要创建对象,还需要建立类与类之间的关系,因此在控制反转的基础上又提出了依赖注入

1、在service组件中生命需要依赖的对象userDao,并提供set方法

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

2、在applicationContext.xml配置文件中,将userDao依赖注入给service

<bean id="aa" class="com.zx.UserDaoImpl">
    </bean>
    	<bean id="userDao" class="com.zx.UserServiceImpl">    
            <property name="userDao" ref="aa"/>
        </bean>

3、测试

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.save("赵翔");
System.out.println(userService);//com.zx.UserServiceImpl@3e9b1010

[注入方式】

? 1、set注入(使用成员变量方法注入给属性赋值)

? 2、构造注入(使用构造方法形式进行属性赋值)

? 3、自动注入(通过在配置文件中完成属性的赋值)

【SET注入】

1、需要谁就提供谁的成员变量以及set方法

2、在applicationContext.xml中声明属性并使用value进行赋值

public class UserServiceImpl implements UserService {    
private UserDao userDao;    

private String name;    
public void setName(String name) {        
this.name = name;    
}
<!--对属性name赋值-->
    <property name="name" value="肥肥"/>
public void save(String name) {    
	userDao.save(name);   
    System.out.println(this.name);
}

3、注入对象类型:引用类型,统一使用ref进行属性注入

4、数组(普通类型)

? 提供成员变量数组以及set方法

for (String sz: pp     
    ) {   
    	System.out.println(sz);
      }

? 属性赋值

<!--数组赋值-->
<property name="pp" >    
    <array value-type="java.lang.String">        
        <value>小肥</value>        
        <value>小猪</value>        
        <value>小胖</value>        
        <value>小仔</value>    
    </array>
</property>

5、数组(对象类型)

private UserDao[] userDaos;
public void setUserDaos(UserDao[] userDaos) {
        this.userDaos = userDaos;
    }

System.out.println("数组对象赋值");
        for (UserDao sz2: userDaos
             ) {
            System.out.println(sz2);
        }
<!--数组对象赋值-->
<property name="userDaos">    
  <array>        
    <ref bean="aa"/>        
    <ref bean="aa"/>        
    <ref bean="aa"/>    
  </array>
</property>

Spring默认注入的是单例模式,所以注入三次的三个对象都是同一个

6、List集合

private List<String> hobbies;
public void setHobbies(List<String> hobbies) {    this.hobbies = hobbies;}
 System.out.println("==========遍历集合");
        hobbies.forEach(hobby-> System.out.println("hobby = "+hobby));
    }
<!--List集合-->
<property name="hobbies">    
  <list>        
    <value>看书</value>        
    <value>睡觉</value>        
    <value>音乐</value>    
  </list>
</property>

因此,list用list标签,普通类型:value 引用 ref

	  `map`用`map`标签,普通类型:`entry  key =xxx  value =xxx `  引用  `key-ref  = xxx value-ref = xxx`

? setset标签,普通类型:value 引用 ref

? propertiesprop标签,key = xxx value

【构造注入】

使用类中的构造方法给属性赋值的方法

语法:

? 1、需要谁就将谁设为成员变量并提供公开的构造方法

? 2、在配置文件中对应的组件标签内部使用<constructor-args>标签进行注入

private String address;
public UserServiceImpl(String address) {    this.address = address;}
System.out.println(this.address);

? index 是指索引,从0开始,name就是构造方法中的参数,value就是赋值

<constructor-arg index="0" name="address" value="北京"/>
【自动注入】

? 1、底层原理也是set方式注入

? 2、自动注入需要在对应组件标签开启才能使用

? 3、【只能用于引用类型的注入|对象类型|组件类型的注入】

语法:

? 1、需要谁就将谁声明为成员变量,并提供set方法

? 2、在对应的组件标签中上加入autowire属性并指定自动注入方式即可

1)autowire = byType 根据类型完成自动注入,根据成员变量的类型去spring工厂里找,找到对应赋值,找不到不赋值


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

这里需要的是userDao,就根据userDao的类型去找,找到了就自动注入进行赋值

<bean id="userDao" class="com.zx.UserDaoImpl"></bean>

<bean id="userService" class="com.zx.UserServiceImpl" autowire="byType">

2)autowire = byName 根据名称完成自动注入,根据成员变量的名称去spring工厂里找,找到对应赋值,找不到不赋值

<bean id="userDao" class="com.zx.UserDaoImpl"></bean>

【如果工厂中存在多个类型一致的组件,使用类型注入会报错】

【Spring中工厂创建对象的模式】

【工厂默认在管理对象都是 单例模式 ,单例模式无论在工厂中获取多少次对象都是同一个对象】

1)默认spring在管理组件对象是 【单例创建】 【singleton】

<bean id="userService" class="com.zx.UserServiceImpl" autowire="byType" scope="singleton">

2)修改为【多例】

<bean id="userService" class="com.zx.UserServiceImpl" autowire="byType" scope="prototype">

scope:用来指定创建工厂的模式 默认值是【单例 singlteton】

如果采用的是【多例】,那么每一次拿到的对象都是崭新的对象

3)spring工厂创建对象的原理

? 【反射+构造方法】

反射:

<bean id="userService" class="com.zx.UserServiceImpl" autowire="byType">
//工厂原理
UserService user = (UserService) Class.forName("com.zx.UserServiceImpl").newInstance();
System.out.println(user);//com.zx.UserServiceImpl@9660f4e

4)spring工厂管理组件生命周期

<bean id="userService" class="com.zx.UserServiceImpl" init-method="init" destroy-method="destory">
public void init(){    
    System.out.println("组件对象初始化");
}
public void destory(){    
    System.out.println("组建对象销毁");
}
//开启工厂
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 //关闭工厂
((ClassPathXmlApplicationContext)context).close();

? a)组件对象什么时候创建?

? 单例对象:工厂启动,所有的单例对象随之创建,工厂销毁,所有的单例对象随之销毁

? 多例对象:每次在工厂中使用时创建 spring工厂不负责多例对象的销毁 而是jvm负责垃圾回收

? b)组件对象什么时候销毁?

【spring好处】

1、解耦合,使用配置文件管理java对象,在生产环境中更换类的实现时不需要重新部署,修改文件即可

2、减少JVM内存的使用,spring默认使用单例的模式创建bean,减少内存的占用

3、 通过【依赖注入】建立组件之间 | 对象之间依赖关系,方便进行组件代码维护和管理

=========================================================================================

【AOP 面向切面编程】

【(proxy)代理的引言】

? 1、代理对象:在整个业务逻辑中完成(传话)(附加操作)的作用,同时也可以中断整个业务

? 2、【好处】:既可以保证原始业务逻辑,原始业务功能不变的情况同时还可以完成一些附加的操作

1631168201060

【如何开发一个代理对象】

? 1、代理对象和业务逻辑对象 | 原始逻辑对象 | 真正的业务逻辑对象 实现相同的接口【小丽闺蜜必须和小丽实现同一个接口,才能和小张进行聊天】

? 2、 代理对象中是【依赖】原始的业务逻辑对象 【小丽闺蜜在传话的时候离不开小丽本人】

创建代理对象的目的:保证原始功能不变的情况下 完成业务逻辑中附加操作 业务层更专注于业务逻辑的开发

【静态代理】

? 1、为每一个业务逻辑通过手动的方法开发对应的代理对象的过程

? 2、在配置文件中注入目标对象

<bean id="userService" class="com.staticProcy.UserServiceImpl"/>
	<bean id="userServiceProxy" class="com.staticProcy.UserServiceProxy">    
    	<!--依赖真正的业务逻辑对象-->    
    		<property name="userService" ref="userService"/>

原始业务逻辑对象:Target Object | 目标对象

【动态代理】
public class TestDynamicProxy {    
    public static void main(String[] args) {        
        //使用动态代理对象:指的是在程序运行的过程中动态通过代码的方式为指定的类生成动态代理对象 
        //Proxy:  用来生成动态代理的类        
        //参数1 : classLoader 类加载器        
        //参数2 : Class[] 创建动态代理对象的接口的数组        
        //参数3 : InvocationHandler: invoke()        
        //返回值: 就是创建好的动态代理对象        
        //目标类        
        UserService userService = new UserServiceImpl();        
        System.out.println(userService);
        //原始实现com.staticProcy.UserServiceImpl@6f94fa3e     
        //读取类信息,加载到内存中,才能为他对应的生成动态代理对象        
        //所以需要类加载器来加载类信息        
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();        
        Class[] classes = {UserService.class};        
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {           
            @Override            
            //在通过动态代理对象调用自己的代理方法时,会优先执行invocationHandler类中的invoke 
            /*            
            * 参数1:当前创建好的代理对象            
            * 参数2:当前代理对象执行的方法对象            
            * 参数3: 当前代理对象执行方法的参数            
            * */            
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在用mybatis生成mapper文件的时候,也是没有手动写实现类的,底层同样是使用了动态代理的理念   
//userDao = sqlSession.getMapper(userDao.class)                
//mybatis 的 mapper文件的解析就是在invoke方法中执行的 根据method.getName()获得方法名,去找到id="方法名"     //再用sql+jdbc+pstm args 进行解析                
//因此方法不能重载,要保证方法名的唯一性                
                System.out.println("开启事务");                
                System.out.println("当前执行的方法"+method.getName()); 
                System.out.println("当前方法的参数:"+args[0]);                
                //开启事务                
                //当前执行的方法findAll                
                //当前方法的参数:赵翔                
                try {                    
                    System.out.println("开启事务");                    
                    //调用目标类中业务方法【通过反射机制 调用目标类中的当前的方法】  
                    Object invoke = method.invoke(new UserServiceImpl(),args);  
                    System.out.println("提交事务");
                    return invoke;
                }catch (Exception e){ 
                    e.printStackTrace(); 
                    System.out.println("回滚事务"); 
                } 
                return null; 
            }  
        }); 
        System.out.println(proxy.getClass());
        //动态代理对象  class com.sun.proxy.$Proxy0        
        String result = proxy.findAll("赵翔");//通过动态代理对象调用代理中的方法    
        System.out.println(result);   
    }
}

面向切面编程底层就是java代理设计模式 【动态代理】

好处:

? 在保证原始业务功能不变的情况下,通过【代理对象】完成业务中的附加操作

? 将业务中核心操作放在目标对象中执行,实现了附加操作和核心操作解耦

通知(Advice):除了目标方法意外的操作都称之为通知,附加功能、事务通知、日志通知、性能通知…

切入点(Pointcut):指定开发好的通知 应用于项目中哪些组件中哪些方法 一般多用于service层

切面(Aspect) = 通知(Advice) + 切入点(Pointcut)

在执行代理方法之前的通知叫

【前置通知】:MethodBeforeAdvice

之后的叫【后置通知】:AfterReturningAdvice

异常的叫【异常通知】:ThrowsAdvice

【环绕通知】:MethodIntercept -----> 【事务】

是所有通知类型中功能最为强大的, 能够全面地控制连接点. 甚至可以控制是否执行连接点.

对于环绕通知来说, 连接点的参数类型必须是 ProceedingJoinPoint . 它是JoinPoint 的子接口, 允许控制何时执行, 是否执行连接点.

在环绕通知中需要明确调用 ProceedingJoinPointproceed()方法来执行被代理的方法. 如果忘记这样做就会导致通知被执行了, 但目标方法没有被执行.

注意: 环绕通知的方法需要返回目标方法执行之后的结果, 即调用 joinPoint.proceed();的返回值, 否则会出现空指针异常

AOP 面向切面编程 :1、开发通知类(附加功能) 2、配置切面点 3、组装切面(Aspect)

步骤:

? 1、加入aop相关依赖 spring-aop、spring-expression、spring-aspect

? 2、项目开发额外功能通知

? 3、配置切面 apllicationContext.xml

? a)注册通知类 <bean id = "" class = "xxxAdvice">

? b)组装切面aspect = advice + pointcut

? <aop:config>

? <aop:pointvut>

? <aop:advisort>

? </aop:config>

前置通知
# 目标对象
public class EmpServiceImpl implements EmpService {    
    @Override    
    public void save(String name) {        
        System.out.println("处理业务逻辑调用save  Dao"+name);    
    }    
    @Override    
    public String find(String name) {        
        System.out.println("处理业务逻辑调用save  Dao"+name);        
        return name;    
    }
# 需要实现前置通知类MethodBeforeAdvice
    
//自定义记录业务方法名称前置通知(目标方法执行之前先执行的额外操作)
public class MyBeforeAdvice  implements MethodBeforeAdvice {    
    //before    
    /*    
    * 参数1:当前执行方法对象、    
    * 参数2:当前执行方法的参数    
    * 参数3:目标对象    * */    
    @Override    
    public void before(Method method, Object[] objects, Object o) throws Throwable {        
        System.out.println("===========开启日志记录=========");
        System.out.println("当前执行的方法:"+method.getName());   
        System.out.println("当前执行的方法参数:"+objects); 
        System.out.println("当前执行的方法的目标对象:"+o);   
        System.out.println("===========结束日志记录=========");
    }
# applicationContext.xml文件
<!--管理Service组件对象-->
    <bean id="empService" class="com.aop.EmpServiceImpl"></bean>
        <!--注册通知-->
        <bean id="myBeforeAdvice" class="com.aop.MyBeforeAdvice"/>
            <!--组装切面-->    
            <aop:config >        
                <!--配置切入点  id:切入点在工厂中的唯一标识        
                    expression表达式:用来指定切入项目中哪些组件哪些方法 
                    execution(返回值 包.类名.*(..))        -->       
 <!--<aop:pointcut id="pc" expression="execution(* com.aop.EmpServiceImpl.*(..))"/>-->         
    <!--配置切面        
    advice-ref:工厂中通知id        
        pointcut-ref:工厂切入点唯一标识
            -->        
            <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="pc"/>    </aop:config>

配置文件中管理了service组件

注册通知 需要创建通知类实现对应的类方法

配置切入点,声明对哪个组件的哪个方法进行切入

将通知和切入点的id进行绑定配置

测试:

public static void main(String[] args) {    
    ApplicationContext context = new ClassPathXmlApplicationContext("/aop/applicationContext.xml"); 
    EmpService empService = (EmpService) context.getBean("empService");    
    empService.save("赵翔");
}

===开启日志记录=
当前执行的方法:save
当前执行的方法参数:[Ljava.lang.Object;@23282c25
当前执行的方法的目标对象:com.aop.EmpServiceImpl@7920ba90
===结束日志记录=
处理业务逻辑调用save Dao赵翔

只要是被切入的方法就不再是普通的对象而是代理对象,代理对象执行

【环绕通知】
public class DeptServiceImpl implements DeptService {    
    private DeptDAO deptDAO;    
    public void setDeptDAO(DeptDAO deptDAO) {        
        this.deptDAO = deptDAO;    
    }    
    @Override        
    public String find(String name) {       
        System.out.println("处理find业务逻辑");
        String s = deptDAO.find(name);    
        try {        
            Thread.sleep(1000);     
        } catch (InterruptedException e) {     
            e.printStackTrace();      
        }        
        throw new RuntimeException("执行出错了!!!!!!");    
    }

自定义环绕通知

//自定义环绕通知,记录目标的方法的执行时长
public class MethodTimeAdvice implements MethodInterceptor {    
    /*   
    这里就是动态代理的invoke方法  
    参数是被spring包装成了methodInvocation 
    methodInvocation:获取当前执行方法  获取当前执行方法的参数  获取目标对象   
    * */  
    @Override   
    public Object invoke(MethodInvocation methodInvocation) throws Throwable { 
        System.out.println("进入环绕通知");   
        /*  System.out.println("当前执行方法:"+methodInvocation.getMethod().getName());   
        System.out.println("当前方法的参数:"+methodInvocation.getArguments()[0]);  
        System.out.println("当前目标对象:"+methodInvocation.getThis());*/   
        try {        
             long start = new Date().getTime();  
             //放行目标方法      
             Object proceed = methodInvocation.proceed();//!!!!!!!!!!!重点!     
             long end = new Date().getTime();     
System.out.println(methodInvocation.getMethod().getName()+"方法执行所用时间为:"+(end-start)+"秒");   
             return proceed;//回到目标方法执行   
            }catch (Exception e){ 
            e.printStackTrace();   
            System.out.println("出现异常!"); 
        }    
        return null;   
    }

配置

 <!--管理DAO组件-->    
     <bean id="deptDAO" class="com.round.impl.DeptDAOImpl"></bean>  
         <!--管理service组件--> 
         <bean id="deptService" class="com.round.service.impl.DeptServiceImpl">   
             <!--注入-->        
             <property name="deptDAO" ref="deptDAO"/>  
             </bean>
 <!--注册通知类-->   
             <bean id="methodTimeAdvice" class="com.round.advices.MethodTimeAdvice"></bean>    
                 <!--配置切面-->   
                 <aop:config>    
<aop:pointcut id="pc" expression="execution(* com.round.service.impl.*ServiceImpl.*(..))"/>   
    <!--组装切面-->      
    <aop:advisor advice-ref="methodTimeAdvice" pointcut-ref="pc"/>    
        </aop:config>

测试

public static void main(String[] args) {    
    ApplicationContext context = new ClassPathXmlApplicationContext("/round/applicationContext.xml"); 
    DeptService deptService = (DeptService) context.getBean("deptService");  
    System.out.println(deptService.getClass().getName());  
    deptService.find("赵翔");
}
切入点表达式

1、expression="execution()"

? 切入点表达式------->方法级别的切入点表达式 控制粒度 :方法级别 效率低

? 完整语法:

? 1、execution(访问权限修饰符 返回值 包名.类名.方法名(参数类型))

? 2、execution(返回值 包名.类名.方法名(参数类型))

? *任意多个字符

例如:1)execution(* com.zx.service.*.*(..)) 表示com.zx.service包下的任意方法任意参数任意返回值

? 2)execution(* com.zx.service..*.*(..)) 表示com.zx.service包及子包中的子包下的任意方法任意参数任意返回值
? 3)execution(* *.*(..)) 表示全部方法 避免使用
2、expression="within()" 切入点表达式------->类级别的切入点表达式 控制粒度 :类级别 效率高

? 完整语法:

? 1、within(包名.类名)

例如:1)within(com.zx.service.*ServiceImpl) 表示service包下的所有以ServiceImpl结尾的类

有关异常通知,不是必须重写的,但是需要有方法存在。

异常通知不可以和后置通知同时存在,因为后置通知肯定是在目标方法成功执行之后执行的

Spring如何创建复杂对象

Spring原理是什么,是如何创建对象的?

1)组件对象 UserDAO userDAOImpl UserService UserServiceImpl

2)工厂创建

<bean id = "userDAO" class = ""com.baizhi.dao.UserDAOImpl>

3)获得组件对象

UserDAO userDAO = (UserDAO) new ClassPathXmlApplicationContext("applicationContext.xml");

4)工厂原理【反射机制,Class.forName(“com.baizhi.dao.UserDAOImpl”).newInstance();】调用类中构造方法进行创建对象


通过工厂创建简单对象

? 简单对象:类中含有构造方法的,可以直接通过new关键字创建的对象 统一称为简单对象

? 工厂创建时:<bean id="" class=""> `

通过工厂创建复杂对象

? 复杂对象:不能直接通过new关键字创建的对象

? 比如接口类型(jdbc中的Connection)、抽象类类型(Calendar(日历)、MessageDigest(加密))

? Calendar需要用getCalendar()静态方法来创建对象

? Connection需要用DriverManager.getConnection("url","username","password")来创建对象

Spring工厂创建复杂对象的方式:

类 implements FactoryBean<Calendar | Connection | 想要创建的复杂对象>{}

所以需要创建复杂对象的时候,需要自己写一个类来实现FactoryBean<>,<>中就是你想创建的复杂对象

步骤:

1、创建复杂对象类实现FactoryBean<复杂对象>

public class CalendarFactoryBean implements FactoryBean<Calendar> {
    //用来书写复杂对象的创建方式  
    @Override  
    public Calendar getObject() throws Exception {   
        return Calendar.getInstance(); 
    }
    //指定创建的复杂对象的类型 
    @Override  
    public Class<?> getObjectType() {    
        return null;  
    }
    //用来指定创建的对象的模式,true是单例,false是多例 
    @Override   
    public boolean isSingleton() {     
        return false; 
    }
}

2、通过工厂配置创建复杂对象

<!--通过factoryBean创建复杂对象-->    <bean id="calendarFactoryBean" class="com.zx.factoryBean.CalendarFactoryBean"/>

3、测试

public static void main(String[] args) {    
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
    Calendar factoryBean = (Calendar) context.getBean("calendarFactoryBean");  
    System.out.println(factoryBean.getTime());
}

Spring整合Mybatis

1、加入依赖 mysql spring mybatis mybatis-spring durid spring-tx

2、配置applciationContext.xml

<!--注入-->   
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">   
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>    
            <property name="url" value="jdbc:mysql://localhost:3306:mimissm"/>   
            <property name="username" value="root"/> 
            <property name="password" value="root"/>  
            </bean>  
            <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
                <!--依赖数据源对象-->  
                <property name="dataSource" ref="dataSource"/>  
            </bean>

进入SqlSessionFactoryBean源码可以看到,同样是实现了FactoryBean,就如上面管理复杂对象一样,需要手动创建XxxFactoryBean来实现FactoryBean

mybatis-spring jar包中,封装了sqlSessionFactory对象的创建

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>
    
    private Resource configLocation;
    private Configuration configuration;
    private Resource[] mapperLocations;
    private DataSource dataSource;

注意:使用了官方提供的sqlSessionFactoryBean后,就不能再使用mybatis-config.xml

Spring整合Mybatix的DAO开发

1、domain

2、dao接口

3、mapper

<mapper namespace="com.zx.dao.UserDao"> 
    <select id="findAll" resultType="com.zx.domain.User">   
   		 select id,name,age from user;    
	</select>
</mapper>

4、applicationContext.xml

<!--创建sqlSessionFactoryBean对象-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
        <!--依赖数据源-->  
        <property name="dataSource" ref="dataSource"/>
        <!--注册mapper配置文件--> 
        <property name="mapperLocations" value="classpath:com/zx/mapper/UserDaoMapper.xml"/> 
        <!-- 配置事务性-->   
        <property name="transactionFactory">    
        <bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />   
            </property>
            </bean>
            <!--创建数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
                <property name="url" value="jdbc:mysql://localhost:3306/springboot"/>  
                <property name="username" value="root"/>    
                <property name="password" value="root"/>
</bean>

5、测试

public static void main(String[] args) {   
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
    SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory"); 
    SqlSession sqlSession = sqlSessionFactory.openSession(); 
    UserDao userDao = sqlSession.getMapper(UserDao.class);   
    userDao.findAll().forEach(user -> System.out.println(user));
}

继续封装:

测试

在这里直接找到bean为userDao的id,userDao下注入了sqlSessionFactory和创建的接口,然后 sqlSessionFactory依赖数据源,最后访问到数据,所以这里测试就不需要再写 SqlSession sqlSession = sqlSessionFactory.openSession();UserDao userDao = sqlSession.getMapper(UserDao.class);

public static void main(String[] args) {  
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
    UserDao userDao = (UserDao) context.getBean("userDao"); 
    userDao.findAll().forEach(user -> System.out.println(user));
}

配置文件,MapperFactoryBean同样实现了FactoryBean

<!--创建DAO组件类-->  
    <bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!--注入sqlSessionFactory--> 
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>  
        <!--注入所创建的dao接口-->  
        <property name="mapperInterface" value="com.zx.dao.UserDao"/>
    </bean>

log4j

1、 引入依赖

<dependency>  
    <groupId>org.apache.logging.log4j</groupId>  
    <artifactId>log4j-core</artifactId> 
    <version>2.14.1</version>
    </dependency>
<dependency> 
    <groupId>org.slf4j</groupId> 
    <artifactId>slf4j-log4j12</artifactId> 
    <version>1.7.30</version>
</dependency>

2、引入log4j.properties配置文件

? 【注意:必须放在resources根目录下,名字叫log4j.properties】

# 根日志
log4j.rootLogger=ERROR,bb
log4j.appender.bb=org.apache.log4j.ConsoleAppender
log4j.appender.bb.layout=org.apache.log4j.PatternLayout
log4j.appender.bb.layout.conversionPattern=[%p] %d{yyyy-MM-dd} %m%n 
#子日志
log4j.logger.com.zx.dao=DEBUG
log4j.logger.org.springframework=DEBUG

事务

propagation:事务传播属性

? REQUIRED:需要事务,如果外层没有事务,则开启新的事务,如果有,融入当前事务(增删改)

? SUPPORTS:支持事务如果外层没有事务,不会开启新的事务,如果有,融入当前事务(查)

? REQUIRES_NEW:每次开启新事务 如果外层存在事务,外层事务挂起,自己开启新的事务,执行完成,恢复外层事务继续执行

? NOT_SUPPORT:不支持事务,如果外层存在事务,外层事务挂起,自己以非事务方式执行,执行完成,恢复外层事务执行

? NEVER:不能存在事务 存在事务报错

? MANDATORY:强制事务 没有事务报错

? NESTED:嵌套事务 事物之间可以嵌套运行

?

<!--设置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource"/>
    </bean>
<!--添加事务的切面-->
    <tx:advice id="myadvice" transaction-manager="transactionManager">  
        <tx:attributes> 
<!--查询的时候,只读,不会因为增删改而产生影响-->   
            <tx:method name="*select*" read-only="true"/>
            <tx:method name="*find*" read-only="true"/>    
            <tx:method name="*get*" read-only="true"/> 
            <tx:method name="*search*" read-only="true"/>
<!--增删改    需要支持事务-->  
            <tx:method name="*insert*" propagation="REQUIRED"/> 
            <tx:method name="*add*" propagation="REQUIRED"/>  
            <tx:method name="*save*" propagation="REQUIRED"/>      
            <tx:method name="*update*" propagation="REQUIRED"/>     
            <tx:method name="*modify*" propagation="REQUIRED"/>     
            <tx:method name="*set*" propagation="REQUIRED"/> 
            <tx:method name="*change*" propagation="REQUIRED"/>  
            <tx:method name="*delete*" propagation="REQUIRED"/>  
            <tx:method name="*clear*" propagation="REQUIRED"/> 
            <tx:method name="*remove*" propagation="REQUIRED"/>   
<!--如果都不匹配  那么就支持事务即可 不需要添加事务-->    
            <tx:method name="*" propagation="SUPPORTS"/>   
                </tx:attributes>
                    </tx:advice>

isolation:事务隔离级别

DEFAULT:使用数据库默认的隔离级别(推荐)

READ_UNCONMMITTED:读未提交 一个客户端读到了另一个客户端没有提交的数据(脏读)

READ_CONMMITTED:读提交 用来避免脏读现象 一个客户端只能读到另一个客户端提交的数据【Oracle】

REPEATABLE_READ:可重复读 主要是用来避免不可重复读现象 也叫 【行锁】 【MySQL】

? 【不可重复读:在一次业务操作中,多次读同一条数据读出数据不一致的现象】

SERIALIZABLE:序列化 最高隔离级别 主要是用来避免 幻读 现象 【表加锁】

? 【幻读:在一次业务操作中,多次读数据发现数据条数不一致,幻影读】

【注意:隔离级别越高,对项目中的查询效率越低 一般推荐数据库默认隔离级别】

read-only:事务读写性,true:只读,不能执行增删改的操作 false 可读可写【MySQL支持,Oracle不支持】

rollback-for:出现什么异常回滚---->默认出现RunTimeExeception及其子类异常进行回滚

no-rollback-for:出现什么异常不回滚 例如 no-rollback-for = "java.lang.RunTimeExeception"

timeout:事务超时性 -1 永不超时 >0 代表设置超时时间 单位 秒

注解式开发

前置条件:在Spring工厂中配置注解扫描

? <context:component-scan base-package="com.zx"/>

1、创建对象相关注解

1、@Component注解

? a)用来负责对象的创建 只能用在类上 <bean id="" class = ""/>

? b)默认使用这个注解在工厂中的对象名是 类名首字母小写

? c)有一个value属性,作用就是指定对象在工厂中的唯一标识,也就是id

2、@Repository注解

? a)一般用来创建DAO中组件的注解

3、@Controller

? a)一般用来创建Controller组件中的注解

4、@Service

? a)一般用来创建Service组件中的注解

2、控制对象在工厂中创建次数

a、配置文件中修改<bean id = "" class = "" scope = "singleton | prototype"/>

b、注解式: @Scope 用来指定对象的创建次数 【默认单例】 只能加载类上 value属性:singleton 单例 prototype多例

3、属性注入的相关注解

? a.·spring·框架提供的 @Autowire 默认根据类型注入

? b.·javaEE·中本身就有 @Resource 默认根据名字注入 名称找不到再根据类型注入

修饰范围:用在类中的成员变量上,或者是类中成员变量的SET方法上

作用:用来完成成员变量的赋值 | 注入操作

【注意:使用注解进行注入时, 日后注入的成员变量可以不再提供SET方法 】

4 控制事务注解

一般用在业务层

@Transactional

? 作用:用来给类中方法加入事务控制,简化配置文件中的 事务通知及事务细粒度配置 以及 简化事务切面配置

修饰范围:类 | 方法上 局部优先原则

? 1、加在类上 代表类中所有方法加入事务控制

? 2、加在方法上 代表当前方法加入事务控制

? 3、类和方法上同时存在 方法优先

使用需求:想要·@Transactional·生效,必须在配置文件中加入

1、设置事务管理器

<!--设置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
<property name="dataSource" ref="dataSource"/>
</bean>

2、开启注解式事务生效

<tx:annotation-driven transaction-manager="transactionManager"/>

tory注解

? a)一般用来创建DAO中组件的注解

3、@Controller

? a)一般用来创建Controller组件中的注解

4、@Service

? a)一般用来创建Service组件中的注解

2、控制对象在工厂中创建次数

a、配置文件中修改<bean id = "" class = "" scope = "singleton | prototype"/>

b、注解式: @Scope 用来指定对象的创建次数 【默认单例】 只能加载类上 value属性:singleton 单例 prototype多例

3、属性注入的相关注解

? a.·spring·框架提供的 @Autowire 默认根据类型注入

? b.·javaEE·中本身就有 @Resource 默认根据名字注入 名称找不到再根据类型注入

修饰范围:用在类中的成员变量上,或者是类中成员变量的SET方法上

作用:用来完成成员变量的赋值 | 注入操作

【注意:使用注解进行注入时, 日后注入的成员变量可以不再提供SET方法 】

4 控制事务注解

一般用在业务层

@Transactional

? 作用:用来给类中方法加入事务控制,简化配置文件中的 事务通知及事务细粒度配置 以及 简化事务切面配置

修饰范围:类 | 方法上 局部优先原则

? 1、加在类上 代表类中所有方法加入事务控制

? 2、加在方法上 代表当前方法加入事务控制

? 3、类和方法上同时存在 方法优先

使用需求:想要·@Transactional·生效,必须在配置文件中加入

1、设置事务管理器

<!--设置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
<property name="dataSource" ref="dataSource"/>
</bean>

2、开启注解式事务生效

<tx:annotation-driven transaction-manager="transactionManager"/>
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:08:22  更:2021-10-09 16:11:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:34:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码