当前位置: 首页 > news >正文

万网网站域名多少钱一年九江建网站报价

万网网站域名多少钱一年,九江建网站报价,广西网站设计服务,企业建站找哪家文章目录 1. Spring2. IOC 控制反转2-1. 通过配置文件定义Bean2-1-1. 通过set方法来注入Bean2-1-2. 通过构造方法来注入Bean2-1-3. 自动装配2-1-4. 集合注入2-1-5. 数据源对象管理(第三方Bean)2-1-6. 在xml配置文件中加载properties文件的数据(context命名空间)2-1-7. 加载容器… 文章目录 1. Spring2. IOC 控制反转2-1. 通过配置文件定义Bean2-1-1. 通过set方法来注入Bean2-1-2. 通过构造方法来注入Bean2-1-3. 自动装配2-1-4. 集合注入2-1-5. 数据源对象管理(第三方Bean)2-1-6. 在xml配置文件中加载properties文件的数据(context命名空间)2-1-7. 加载容器的其他方式2-1-8. p命名空间2-1-9. c命名空间2-1-10. util命名空间 2-2. 通过注解加载Bean2-2-1. 选择性实例化Bean2-2-2. 纯注解加载Bean2-2-3. 自动装配2-2-4. 简单类型的注入2-2-5. 管理第三方Bean 2-3. Bean的实例化方式2-3-1. 通过构造方法来实例化Bean2-3-2. 通过简单工厂模式实例化2-3-3. 通过工厂方法模式来实例化2-3-4. 通过FactoryBean接口实例化2-3-5. BeanFactory 和 FactoryBean 的区别2-3-6. FactoryBean 的应用(以自定义Date类型举例) 2-4. Bean的生命周期5步2-4-1. Bean 的生命周期之7步2-4-2. Bean 的生命周期之10步2-4-3. Bean的作用域2-4-4. 自己实例化的对象让spring容器去管理 2-5. Bean 循环依赖问题2-5-1. set注入 单例模式之循环依赖2-5-2. 构造器注入 单例模式之循环依赖2-5-3. Spring 解决循环依赖的机理 2-6. 自定义 spring 框架 3. Spring之JdbcTemplate4. Spring 代理模式4-1. jdk 之动态代理4-2. cglib 之动态代理4-3. jdk 与 cglib 动态代理的区别 5. 面向切面编程 AOP6. Spring 事务6-1. 事务的传播特性6-2. 事务的隔离级别6-3. 事务的超时时间6-4. 设置事务只读(readOnly) 1. Spring 主要包括两种功能分别为IOC(Inverse Of Control意为着控制反转用于反转创建Bean的控制权。通过使用ioc可以降低代码的耦合度耦合度指的是类与类之间的依赖关系如果耦合度高表明类与类之间的依赖关系越紧密此时如果修改其中的一些代码可能会造成其他类出错的情况对于后期的维护及其不便。使用ioc容器管理的Bean推荐使用实现接口的实现类)、AOP(Aspect Oriented Programming意为面向切面编程)。 2. IOC 控制反转 IOC意为控制反转也就是反转创建Bean的控制权。在这之前我们需要调用一个类下的某个方法时通常做法是首先对这个类进行实例化然后再调用其实例化对象的方法。通过IOC把这个创建类交给一个容器去管理我们需要用到时只需要从容器中去拿即可。当然前提是我们需要定义配置文件当然随着版本的迭代后期发展到我们只需要添加一些注解即可。 2-1. 通过配置文件定义Bean 这个前提是需要有spring-context的依赖我的这个是SpringBoot项目哈导入这个依赖之后在resources这个目录下鼠标右键找到新建xml配置文件就有对应的配置文件格式了。 具体xml配置文件格式如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduserDao classcom.lz.demo_spring_24_1.dao.UserDao//beans我在这个配置文件里边定义了一个Bean并且这个Bean的名字为userDao此时我们使用java代码就可以从这个容器中去获取这个Bean了。当然首先需要先加载到这个配置文件这里使用 ClassPathXmlApplicationContext去加载加载完之后可以得到一个ioc容器对象此时只需要通过这个ioc容器对象通过getBean即可获取对应的Bean对象。 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.dao.UserDao; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.support.ClassPathXmlApplicationContext;SpringBootTest(classes Test2.class) public class Test2 {Testpublic void test1(){ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(spring-config.xml);UserDao userDao (UserDao) ctx.getBean(userDao);System.out.println(userDao);} }2-1-1. 通过set方法来注入Bean 在一个类下如果需要引入另外一个类的方法前提是需要对这个类实例化。如果使用ioc添加set方法即可还有其他。 package com.lz.demo_spring_24_1.service;import com.lz.demo_spring_24_1.dao.UserDao; public class UserService {private UserDao ud;public void setUd(UserDao ud) {this.ud ud;}public void print(){System.out.println(ud);} }对应的配置文件中需要做的配置如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduserDao classcom.lz.demo_spring_24_1.dao.UserDao/bean iduserService classcom.lz.demo_spring_24_1.service.UserServiceproperty nameud refuserDao//bean /beans测试代码如下 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.service.UserService; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.support.ClassPathXmlApplicationContext;SpringBootTest(classes Test2.class) public class Test2 {Testpublic void test1(){ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(spring-config.xml);UserService us (UserService) ctx.getBean(userService);System.out.println(us);us.print();} }注意需要提醒一下是set注入的配置文件Bean的property属性name值是根据对应类的set方法名来的而不是根据对应Bean的变量名。 上述是错误写法其中name属性值应该修改为abcSdi才对。 另外关于xml配置文件中的其他一些属性。 name属性用于给这个Bean起别名多个别名之间用逗号隔开。 scope属性用于设置对应的Bean是单例还是原型默认情况下是单例的。 可以修改为原型的。对于一个简单类型想在配置文件中注入值只需要设置其value属性即可。 如果想了解哪些类型是简单类型可以去BeanUtils类下找到isSimpleValueType方法查看对应的源码就可以知道。 常见的简单类型有八种基本数据类型、字符串、枚举类型、Class类型、日期类型不过日期类型在配置文件需要写入特定的格式才支持因此通常情况下会把日期类型当作是简单类型来注入。 2-1-2. 通过构造方法来注入Bean 需要添加对应的构造方法即可然后在配置文件中添加对应的构造参数即可。 package com.lz.demo_spring_24_1.service;import com.lz.demo_spring_24_1.dao.UserDao;public class UserService {private UserDao ud;private Integer val;public void setVal(Integer val) {this.val val;}public void setUd(UserDao ud) {this.ud ud;}public UserService(){}public UserService(UserDao ud){this.ud ud;}public UserService(UserDao ud,Integer val){this.ud ud;this.val val;}public void print(){System.out.println(ud val);} }?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduserDao classcom.lz.demo_spring_24_1.dao.UserDao/bean iduserService classcom.lz.demo_spring_24_1.service.UserServiceconstructor-arg nameud refuserDao/constructor-arg nameval value1000//bean/beans上述这样配置存在一个问题那就是耦合度比较高因为这是通过构造方法的变量名来进行注入的比如如果我在类文件里边修改ud为ud1那么此时就需要在配置文件中做对应的修改。此时可以通过设置类型type属性从而解决这个耦合度问题如下 但是如果构造器方法中存在很多相同类型上述解决办法就不行了此时可以通过设置构造器方法中的参数位置index属性来解决。 2-1-3. 自动装配 在xml配置文件中的配置autowire属性即可本质依旧是set注入因此在类文件下依旧需要添加对应的set方法如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduserDao classcom.lz.demo_spring_24_1.dao.UserDao/bean iduserService classcom.lz.demo_spring_24_1.service.UserService autowirebyType/ /beans属性autowire的值也可以修改为byName此时根据的是通过Bean的名字进行注入因此在配置文件中要注入的Bean的id值不能随便取这里需要额外注意一下。上述是根据Bean的类型进行注入的只不过在xml配置文件中要注入的Bean只能为一个否则会报错因为它不知道到底需要注入哪一个。 对应的java类如下 package com.lz.demo_spring_24_1.service;import com.lz.demo_spring_24_1.dao.UserDao; public class UserService {private UserDao ud;public void setUd(UserDao ud) {this.ud ud;}public void print(){System.out.println(ud );} }既然是自动装配那么装配的那个Bean肯定是需要在配置文件中进行定义的。 2-1-4. 集合注入 对应java类参考代码如下 package com.lz.demo_spring_24_1.other;import java.util.*;public class Datas {private int[] arr1;private ListString list1;private SetString set;private MapString,Object map;private Properties properties;public void setArr1(int[] arr1) {this.arr1 arr1;}public void setList1(ListString list1) {this.list1 list1;}public void setSet(SetString set) {this.set set;}public void setMap(MapString, Object map) {this.map map;}public void setProperties(Properties properties) {this.properties properties;}Overridepublic String toString() {return Datas{ arr1 Arrays.toString(arr1) , list1 list1 , set set , map map , properties properties };} }xml配置文件中的配置如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iddatas classcom.lz.demo_spring_24_1.other.Datasproperty namearr1arrayvalue123/valuevalue456/value/array/propertyproperty namelist1listvalue123/valuevalue234/value/list/propertyproperty namesetsetvalue123/valuevalue234/value/set/propertyproperty namemapmapentry keycountry valuechina/entry keyage value100//map/propertyproperty namepropertiespropsprop keycountrychina/propprop keyage100/prop/props/property/bean /beans如果在数组、List、Set中注入非简单类型只需要把value标签修改为ref标签且在ref标签的bean属性中写入对应的Bean的名称即可。 对于map数据类型如果key、value值是非简单类型直接使用key-ref、value-ref即可。 2-1-5. 数据源对象管理(第三方Bean) 这里以druid数据源为例需要导入druid的依赖。 dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.16/version /dependency在对应的xml配置文件中定义的Bean如下这里使用的是set注入由于其并没有对应设置对应配置的构造方法所以使用set注入而不使用构造器注入 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iddataSource classcom.alibaba.druid.pool.DruidDataSourceproperty namedriverClassName valuecom.mysql.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/mytest1/property nameusername valueroot/property namepassword valueroot//bean/beans运行结果 2-1-6. 在xml配置文件中加载properties文件的数据(context命名空间) 前提是需要在xml中开启context命名空间如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd /beans之后需要在xml配置文件中加载properties文件最后修改其中Bean的一些配置即可。propertis文件配置如下 spring.application.namedemo_spring_24_1jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/mytest1 jdbc.usernameroot jdbc.passwordroot此时在xml配置文件中只需要使用${}引入对应的名称即可。 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdcontext:property-placeholder locationapplication.properties/ !-- 使用context空间加载properties文件--bean iddataSource classcom.alibaba.druid.pool.DruidDataSourceproperty namedriverClassName value${jdbc.driver}/property nameurl value${jdbc.url}/property nameusername value${jdbc.username}/property namepassword value${jdbc.password}//bean /beans如果想要加载多个properties文件可以在location属性中用逗号隔开写上其他properties文件即可。 context:property-placeholder locationapplication.properties,application2.properties/上述这种写法并不怎么规范规范写法应该是这样如下 context:property-placeholder locationclasspath:*.properties/如果想不加载系统属性可以在上面context的属性system-properties-mode设置为NEVER即可。 context:property-placeholder locationapplication.properties system-properties-modeNEVER/2-1-7. 加载容器的其他方式 上述方式都是通过加载类路径下的配置文件来进行的其实还可以通过加载绝对路径来进行。 2-1-8. p命名空间 这种方式本质上是set注入因此依旧需要在对应的类文件中添加set方法但是在配置文件中可以简化一些操作而已。是set注入的一种简化而已首先需要对配置文件中添加一点配置参考如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:phttp://www.springframework.org/schema/pxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd/beanspackage com.lz.demo_spring_24_1.entity;import java.util.Date;public class User {private String name;private Date birthDay;public void setName(String name) {this.name name;}public void setBirthDay(Date birthDay) {this.birthDay birthDay;}Overridepublic String toString() {return User{ name name \ , birthDay birthDay };} } 只需要在配置文件以p:变量名后添加对应的值即可因为变量birthDay是日期类型可以使用简单类型也可以使用非简单类型。 运行结果 2-1-9. c命名空间 本质上是构造方法注入因此需要添加对应的构造方法。只是构造器注入的一种简化而已。和p命名空间一样都需要对xml配置文件添加一些配置用以开启c命名空间。 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:chttp://www.springframework.org/schema/cxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iddate classjava.util.Date/bean iduser classcom.lz.demo_spring_24_1.entity.User c:_0张三 c:birthDay-refdate//beans有两种方式可以进行注入一种是通过参数的位置另外一种是通过参数名参考如上运行结果和p命名空间一样。 2-1-10. util命名空间 和上面两种命名空间一样需要在xml配置文件中添加util命名空间的配置。配置如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:utilhttp://www.springframework.org/schema/utilxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd /beans现在假设我想要连接数据库但是可以使用连接池可以用druid、c3p0它们都需要添加一些连接数据库的配置。 并且连接的配置信息都相同此时可以采用util命名空间实现配置复用而已如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:utilhttp://www.springframework.org/schema/utilxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsdutil:properties idproprop keydrivercom.mysql.cj.jdbc.driver/propprop keyurljdbc:mysql://localhost:3306/mytest1/propprop keyusernameroot/propprop keypasswordroot/prop/util:propertiesbean idds1 classcom.lz.demo_spring_24_1.entity.MyDataSource1property nameproperties refpro//beanbean idds2 classcom.lz.demo_spring_24_1.entity.MyDataSource2property nameproperties refpro//bean /beans运行结果如下 2-2. 通过注解加载Bean 这种方式最初的版本依旧需要写xml配置文件同时需要在对应的类上加上注解Component如下 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packagecom.lz.demo_spring_24_1.dao//beans只要是在com.lz.demo_spring_24_1.dao这个目录下所有的添加了Component注解的类都会被容器进行管理。如果需要添加其他包下Bean被spring容器进行管理可以在上述配置文件的包后用逗号隔开之后再添加其他包路径即可。当然也可以写两个包的父包即可。 package com.lz.demo_spring_24_1.dao;import org.springframework.stereotype.Component;Component public class UserDao { }从Component又衍生出其他三种注解分别为Repository数据层、Service业务层、Controller表现层。它们的功能都相同只是为了便于分辨而已。 2-2-1. 选择性实例化Bean 对于一个包下所定义的Bean添加了对应注解的如何在xml配置文件中选择性去选择哪些Bean可以被实例化。比如现在我定义了两个Bean其中一个为a另一个为ba上添加了注解Serviceb上添加了注解Controller现在使用context命名空间扫描这两个bean的父包。然后进行过滤只把有注解Service Bean a添加到spring容器中进行管理参考代码如下 package com.lz.demo_spring_24_1.beans;import org.springframework.stereotype.Controller; import org.springframework.stereotype.Service;Service public class A {public A(){System.out.println(A........);} }Controller class B {public B(){System.out.println(B........);} } xml配置文件写法1 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packagecom.lz.demo_spring_24_1.beans use-default-filterstruecontext:exclude-filter typeannotation expressionorg.springframework.stereotype.Controller//context:component-scan/beansxml配置文件写法2 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packagecom.lz.demo_spring_24_1.beans use-default-filtersfalsecontext:include-filter typeannotation expressionorg.springframework.stereotype.Service//context:component-scan/beans运行结果如下 2-2-2. 纯注解加载Bean 这种模式不需要编写xml配置文件在上述代码不变的基础上新建一个配置类当然需要添加Configuration注解。写这个配置类相当于是代替上面那个xml配置文件。 package com.lz.demo_spring_24_1.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;Configuration ComponentScan(value com.lz.demo_spring_24_1.dao) public class SpringConfig { } 之前是加载那个配置文件xml此时如果想要运行成功需要加载这个配置类。 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.config.SpringConfig; import com.lz.demo_spring_24_1.dao.UserDao; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;import java.sql.SQLException;SpringBootTest(classes Test2.class) public class Test2 {Testpublic void test1() {ApplicationContext ctx new AnnotationConfigApplicationContext(SpringConfig.class);UserDao userDao (UserDao) ctx.getBean(userDao);System.out.println(userDao);} }2-2-3. 自动装配 现在我在数据访问层定义了一个类UserDao还在业务层定义了一个类UserService其中需要在UserService中引用UserDao类下的某个方法。为此需要在UserService中new UserDao在前面知识中了解到可以通过set、构造器、自动装配这三种方式注入UserDao类对象但是上述讲述的是xml配置文件来进行注入的现在如何使用配置类来实现上述那种自动装配的效果呢参考代码如下 package com.lz.demo_spring_24_1.dao;import org.springframework.stereotype.Repository;Repository public class UserDao { } package com.lz.demo_spring_24_1.service;import com.lz.demo_spring_24_1.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;Service public class UserService {Autowiredprivate UserDao ud;public void print(){System.out.println(ud);}}我们只需要在UserService类中使用注解AutoWired这种注入方式即可当然也可以使用注解Resource。它们两者的区别是前者首先是根据类型去对应包下去查找是否存在UserDao这个Bean如果没有再通过Bean名去查找如果两者都没有找到或者出现歧义最终会报错而后者正好相反。Resource注解可以通过name属性指定Bean名如果name值没有指定那么会把变量名当作Bean名来使用。。(也就是说如果此时变量名和对应的Bean名不一致此时再根据类型来进行装配如果没有找到会报错。。。) 如果所注入的Bean有多个比如有多个类都实现了某个接口而且注入的Bean类型使用了泛型此时可以在注解AutoWired下添加注解Qualifier并在Qualifier内写上对应的Bean名当然这个Bean名需要在对应的类上写上才行。如下有一个接口UserDao它有一个方法printUserInfo它有两个实现类UserDaoImpl1、UserDaoImpl2这个类上都添加了注解Repository。然后有一个类UserService添加了注解Service在这个类下需要UserDao的依赖这里直接使用泛型。如下 package com.lz.demo_spring_24_1.beans;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service;Service public class UserService {Autowiredprivate UserDao ud;public void printUserInfo(){ud.printUserInfo();} }此时运行结果如下 因为UserDao有两个实现类此时不知道使用哪个因此报错此时就可以添加注解Qualifier添加对应的Bean名不设置对应Bean名Bean名默认为类名首字母小写。。如下 当然也可以直接使用Resource注解写上对应的Bean名。 另外注解AutoWired也可以放在set方法上及构造方法上如果所注入的Bean只有一个AutoWired可以省略但是需要添加对应的构造方法需要注意的是如果存在默认无参构造方法这样是不行的如下 2-2-4. 简单类型的注入 通过使用注解Value可以注入简单类型如下 package com.lz.demo_spring_24_1.dao;import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository;Repository public class UserDao {Value(lize)private String name;Overridepublic String toString() {return UserDao{ name name \ };} } 不过上述这样写基本上没有任何意义直接在name后面添加等于号并写上对应的值不也是一样吗Value真正意义在于可以注入配置文件properties中的变量如下 首先和上面xml配置一样首先需要在配置类上指明所对应的配置文件需要用到注解PropertySource。 使用的话只需要在Value注解内用${}指明引用哪个变量的值。 运行结果如下 另外Value还可以使用在set方法上以及构造方法上的对应参数上。。 2-2-5. 管理第三方Bean 首先需要定义一个配置类在这个配置类下定义对应Bean的方法。参考代码如下 package com.lz.demo_spring_24_1.config;import com.alibaba.druid.pool.DruidDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource;Configuration public class SpringConfig2 {Beanpublic DataSource dataSource(){DruidDataSource ds new DruidDataSource();ds.setDriverClassName(com.mysql.jdbc.driver);ds.setUrl(jdbc:mysql://localhost:3306/mytest1);ds.setUsername(root);ds.setPassword(root);return ds;} }但是上述方式存在一个问题就是如果我想修改上述一些配置信息此时还需要找到这个类然后再进行修改为此我们可以把上述信息放到配置文件properties中去需要用到时只需要通过Value注解注入即可。 2-3. Bean的实例化方式 这部分有一些内容和前面有重复但是这里相当于是总结了吧 2-3-1. 通过构造方法来实例化Bean 在xml配置文件中定义对应的Bean然后直接通过容器.getBean方法来获取对应的Bean。默认情况下是调用Bean的无参构造方法。。 2-3-2. 通过简单工厂模式实例化 本质上依旧是通过构造方法来实例化Bean参考代码如下 工厂类 package com.lz.demo_spring_24_1.entity.factory;public class Factory1 {public static User getUser(){return new User();}}xml配置文件 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduser classcom.lz.demo_spring_24_1.entity.factory.Factory1 factory-methodgetUser//beans运行结果 2-3-3. 通过工厂方法模式来实例化 本质上依旧是通过构造方法来实例化Bean参考代码如下 工厂类 package com.lz.demo_spring_24_1.entity.factory;public class UserFactory {public User get(){return new User();} } xml配置文件 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduser2Factory classcom.lz.demo_spring_24_1.entity.factory.UserFactory/bean iduser2 factory-beanuser2Factory factory-methodget/ /beans运行结果 2-3-4. 通过FactoryBean接口实例化 可以说是第三种方式的一种简化。参考代码如下: 实现了FactoryBean接口的类 package com.lz.demo_spring_24_1.entity.factory;import org.springframework.beans.factory.FactoryBean;public class UserFactoryBean implements FactoryBeanUser {Overridepublic boolean isSingleton() { // return FactoryBean.super.isSingleton();return true;}// 默认是单例的Overridepublic User getObject() throws Exception {return new User();}Overridepublic Class? getObjectType() {return null;} } xml配置文件 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduser3 classcom.lz.demo_spring_24_1.entity.factory.UserFactoryBean/ /beans运行结果 2-3-5. BeanFactory 和 FactoryBean 的区别 BeanFactory 是spring ioc容器的最顶层对象意为 “Bean工厂”负责创建Bean对象。 FactoryBean 是一个Bean是一个能够辅助 spring 实例化其他Bean对象的一个Bean。在spring中Bean可以分为两类一种为普通Bean另外一种是工厂Bean。 2-3-6. FactoryBean 的应用(以自定义Date类型举例) 从前面可以知道Date这种类型既可以当作是简单类型也可以当作非简单类型。当作简单类型时在xml配置文件中定义时需要输入特定格式否则会报错。而 FactoryBean 是Spring中一种用于辅助实例化其他Bean的Bean为此可以使用 FactoryBean 的形式使在xml文件定义Date 类型的Bean支持自定义格式输入参考代码如下 继承了FactoryBean 接口的类 package com.lz.demo_spring_24_1.entity.factory;import org.springframework.beans.factory.FactoryBean;import java.text.SimpleDateFormat; import java.util.Date;public class DateFactoryBean implements FactoryBeanDate {private String date_str;public DateFactoryBean(String date_str) {this.date_str date_str;}Overridepublic boolean isSingleton() {return true;}Overridepublic Date getObject() throws Exception {SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);// 自定义输入的日期格式return sdf.parse(date_str);}Overridepublic Class? getObjectType() {return null;} }xml配置文件 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iddate classcom.lz.demo_spring_24_1.entity.factory.DateFactoryBeanconstructor-arg namedate_str value2021-01-01//bean/beans运行结果 2-4. Bean的生命周期5步 就是Bean从被创建到销毁的过程。Bean的生命周期可以被划分为5个过程分别是实例化Bean、Bean属性赋值、初始化Bean、使用Bean、销毁Bean。 实例化Bean调用无参数构造方法Bean属性赋值调用set方法初始化Bean调用 Bean 的 init方法需要自己编写代码并进行配置使用Bean销毁Bean调用 Bean 的destory方法需要自己编写代码并进行配置 Bean的声明周期代码演示如下 package com.lz.demo_spring_24_1.entity;// Bean 的生命周期 public class User3 {private String name;public User3() {System.out.println(1. 实例化Bean。。。);}public void setName(String name) {this.name name;System.out.println(2. Bean 参数赋值...);}// 初始化Beanpublic void init(){System.out.println(3. 初始化Bean。。。);}// 销毁 Beanpublic void destory(){System.out.println(5. 销毁Bean。。。);} }?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean iduser classcom.lz.demo_spring_24_1.entity.User3 init-methodinit destroy-methoddestoryproperty namename value张三//bean/beanspackage com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.entity.User3; import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test2025_1 {Testpublic void test3(){ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(spring-2025-3.xml);User3 user3 ctx.getBean(user, User3.class);System.out.println(4. 使用Beanuser3);// 使用Beanctx.close();// 关闭容器只能applicationContext实现类才有close方法。。。} } 运行结果: 2-4-1. Bean 的生命周期之7步 在上面说到Bean的生命周期只有5步7步的说法是在前面5步的基础上添加了2步就是在5步的第4步 初始化Bean 前面加上 执行”Bean后处理器“的before方法在后面加上 执行”Bean后处理器“的fater方法。。。 需要在前面基本上添加一个类这个类需要实现BeanPostProcessor接口。。。,并重写其下面的2个方法。 package com.lz.demo_spring_24_1.entity.interfaces;import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;public class LogBeanPostProcessor implements BeanPostProcessor {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(执行 Bean后处理器 的before方法);return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(执行 Bean后处理器 的after方法);return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);} }另外需要在xml配置文件中配置这个Bean。 之后就可以看到运行结果了。。。 需要注意的是上述添加这个Bean对所有的Bean都会生效。。。也就是说 当前容器对象 getBean 之后获取到Bean都会执行上述两个函数。。。 2-4-2. Bean 的生命周期之10步 在前面7步的基础之上再额外添加3步添加的位置分别为 在 执行”Bean后处理器“的before方法 前面添加 检查 Bean 是否实现了Aware的相关接口并设置相关依赖在 执行”Bean后处理器“的before方法 后面添加 检查 Bean 是否实现了InitializingBean接口并调用接口方法在使用Bean 之后添加了 检查 Bean 是否实现了DispossableBean接口并调用接口方法。 其中Aware的相关接口有BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。 当Bean实现了BeanNameAwarespring会将Bean的名字传递给Bean当Bean实现了BeanClassLoaderAwarespring会将加载该Bean的类加载器传递给Bean当Bean实现了BeanFactoryAwarespring会将Bean工厂对象传递给Bean。 总结而言如果测试生命周期10步需要让对应的类实现5个接口分别为BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、InitializingBean、DispossableBean。 演示代码如下: package com.lz.demo_spring_24_1.entity;import org.springframework.beans.BeansException; import org.springframework.beans.factory.*;// Bean 的生命周期 public class User3 implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {private String name;public User3() {System.out.println(1. 实例化Bean。。。);}public void setName(String name) {this.name name;System.out.println(2. Bean 参数赋值...);}// 初始化Beanpublic void init(){System.out.println(4. 初始化Bean。。。);}// 销毁 Beanpublic void destory1(){System.out.println(7. 销毁Bean。。。);}Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println(Bean的类加载器classLoader);}Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println(Bean的 工厂对象是beanFactory);}Overridepublic void setBeanName(String s) {System.out.println(Bean的名字是s);}Overridepublic void destroy() throws Exception {System.out.println(实现了DisposableBean接口。。。);}Overridepublic void afterPropertiesSet() throws Exception {System.out.println(实现了InitializingBean接口。。。);} } ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean classcom.lz.demo_spring_24_1.entity.interfaces.LogBeanPostProcessor/bean iduser classcom.lz.demo_spring_24_1.entity.User3 init-methodinit destroy-methoddestory1property namename value张三//bean/beans运行结果 2-4-3. Bean的作用域 spring 容器只对 单例的 Bean进行完整的生命周期管理。如果是原型的Beanspring容器只负责将Bean初始化完毕等客户端一旦获取到该Bean之后spring容器就不在管理该对象的生命周期了。如果需要测试的话只需要在xml配置文件的Bean添加属性scope并设置值为原型运行结果如下 2-4-4. 自己实例化的对象让spring容器去管理 直接复制类代码导包让软件去导入。。。 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.entity.User3; import com.lz.demo_spring_24_1.entity.User4; import com.lz.demo_spring_24_1.entity.factory.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Date;public class Test2025_1 {Testpublic void test4(){User4 user4 new User4();System.out.println(user4);DefaultListableBeanFactory beanFactory new DefaultListableBeanFactory();beanFactory.registerSingleton(user,user4);User4 user1 beanFactory.getBean(User4.class);System.out.println(user1);} } 运行结果 2-5. Bean 循环依赖问题 其实就是在一个Bean a中需要Bean b的依赖而在Bean b中又需要Bean a的依赖。 2-5-1. set注入 单例模式之循环依赖 比如如下代码 package com.lz.demo_spring_24_1.entity.xunhuan;public class UserA {private String name;private UserB userB;public void setName(String name) {this.name name;}public void setUserB(UserB userB) {this.userB userB;}Overridepublic String toString() {return UserA{ name name \ , userB userB.getName() };}public String getName() {return name;} } package com.lz.demo_spring_24_1.entity.xunhuan;public class UserB {private String name;private UserA userA;public void setName(String name) {this.name name;}public void setUserA(UserA userA) {this.userA userA;}Overridepublic String toString() {return UserB{ name name \ , userA userA.getName() };}public String getName() {return name;} } xml配置文件 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean idusera classcom.lz.demo_spring_24_1.entity.xunhuan.UserAproperty namename value张三/property nameuserB refuserb//beanbean iduserb classcom.lz.demo_spring_24_1.entity.xunhuan.UserBproperty namename value李四/property nameuserA refusera//bean /beans运行结果 如果上述代码UserA的toString方法中参数直接是UserB并且在UserB的toString方法中参数直接是UserA。此时的结果会报错因为输出UserA这个对象时实际上调用的是重写toString方法而在toString方法中又会输出UserB而在UserB的toString方法下又有UserA此时会陷入si循环。。最终导致内存溢出从而导致报错。 上面是 单例模式 set注入原型模式下不可以 的模式下的运行结果Spring容器在加载的时候进行实例化只要任意一个Bean实例化后马上进行“曝光”不等属性赋值Bean被“曝光”之后再进行属性赋值。在spring中为什么可以解决循环依赖的问题。。。需要注意的是在spring中只有当两个Bean都是原型下才会出现异常但是如果其中有一个是单例的就不会出现异常。。 2-5-2. 构造器注入 单例模式之循环依赖 这种方式是存在问题因为这是直接在Bean a构造方法里面给属性赋值但是其中一个参数Bean b还没有进行实例化而Bean b里边又有一个参数Bean a也没有进行实例化。参考代码如下 package com.lz.demo_spring_24_1.entity.xunhuan;public class UserA {private String name;private UserB userB;public UserA(String name, UserB userB) {this.name name;this.userB userB;}/*public void setName(String name) {this.name name;}public void setUserB(UserB userB) {this.userB userB;}*/Overridepublic String toString() {return UserA{ name name \ , userB userB.getName() };}public String getName() {return name;} } package com.lz.demo_spring_24_1.entity.xunhuan;public class UserB {private String name;private UserA userA;public UserB(String name, UserA userA) {this.name name;this.userA userA;}/*public void setName(String name) {this.name name;}public void setUserA(UserA userA) {this.userA userA;}*/Overridepublic String toString() {return UserB{ name name \ , userA userA.getName() };}public String getName() {return name;} } 也就是说 构造器注入 单例模式 这种方式下spring是无法解决循环依赖问题的。 2-5-3. Spring 解决循环依赖的机理 set注入单例模式下为什么能解决循环依赖问题 根本原因在于这种方式可以将 实例化Bean 和 给Bean属性赋值 这两个动作分开去完成。实例化Bean的时候调用无参构造方法来完成**此刻可以先不给属性赋值可以提前将该Bean对象“曝光”给外界。**给Bean属性赋值的时候调用setter方法来完成。两个过程是完全分开去完成的并且两个过程不要求在同一个时间点上完成。 2-6. 自定义 spring 框架 这里的spring框架只有基本ioc功能且还是通过配置文件的形式。。参考代码如下 myspring核心代码 package com.lz.demo_spring_24_1.myspring.utils;import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map;public class MyBeanFactory {private MapString,Object beanMap new HashMap();// 用来存储bean的哈希表// 在构造方法这里的读取xml配置文件的数据// 然后通过反射机制进行实例化对象之后把实例化后的对象存储到哈希表中进行存储public MyBeanFactory(String configPath) {try{SAXReader reader new SAXReader();InputStream stream ClassLoader.getSystemClassLoader().getResourceAsStream(configPath);Document document reader.read(stream);ListNode nodes document.selectNodes(//bean);// 获取所有的bean标签for (Node node : nodes) {Element ele (Element) node;// 转换成Element类型String id ele.attributeValue(id);String clazz ele.attributeValue(class);// bean 的名称class 字符串Class? aClass Class.forName(clazz);Constructor? constructor aClass.getDeclaredConstructor();Object o constructor.newInstance();beanMap.put(id,o);// 通过反射对bean进行无参实例化}setBeanField(nodes,beanMap);}catch (Exception e){e.printStackTrace();}}/*** 获取bean的方法* beanName : Bean的名称* */public Object getBean(String beanName){return beanMap.get(beanName);}// 给对象属性赋值// 相当于set注入private void setBeanField(ListNode nodes,MapString,Object beanMap){for (Node node : nodes) {try{Element ele (Element) node;String id ele.attributeValue(id);String clazz ele.attributeValue(class);// bean 的名称class 字符串Class? aClass Class.forName(clazz);ListElement properties ele.elements();// 所有的属性标签properties.forEach(property-{try{String name property.attributeValue(name);String value property.attributeValue(value);String ref property.attributeValue(ref);String setName set name.substring(0,1).toUpperCase() name.substring(1);Field field aClass.getDeclaredField(name); // field.setAccessible(true);Class? type1 field.getType();Method setMethod aClass.getDeclaredMethod(setName, type1);Object v value;if(value ! null){// 这个变量是私有的// 简单类型String typeSimpleName type1.getSimpleName();// 属性类型名switch (typeSimpleName){case byte:v Byte.parseByte(value);break;case short:v Short.parseShort(value);break;case int:v Integer.parseInt(value);break;case long:v Long.parseLong(value);break;case boolean:v Boolean.parseBoolean(value);break;case float:v Float.parseFloat(value);break;case double:v Double.parseDouble(value);break;case char:v value.charAt(0);break;case Byte:v Byte.valueOf(value);break;case Short:v Short.valueOf(value);break;case Integer:v Integer.valueOf(value);break;case Long:v Long.valueOf(value);break;case Boolean:v Boolean.valueOf(value);break;case Float:v Float.valueOf(value);break;case Double:v Double.valueOf(value);break;case Character:v Character.valueOf(value.charAt(0));break;}setMethod.invoke(beanMap.get(id),v);}if(ref ! null){// 非简单类型setMethod.invoke(beanMap.get(id),beanMap.get(ref));}}catch (Exception e){e.printStackTrace();}});}catch (Exception e){e.printStackTrace();}}} } 测试类 package com.lz.demo_spring_24_1.myspring;public class User {private String name;private Integer age;private User2 user2;public void setAge(Integer age) {this.age age;}public void setName(String name) {this.name name;}public void setUser2(User2 user2) {this.user2 user2;}Overridepublic String toString() {return User{ name name \ , age age , user2 user2 };} } package com.lz.demo_spring_24_1.myspring;public class User2 { } 配置文件 ?xml version1.0 encodingUTF-8? beansbean iduser classcom.lz.demo_spring_24_1.myspring.Userproperty namename value张三/property nameage value20/property nameuser2 refuser2//beanbean iduser2 classcom.lz.demo_spring_24_1.myspring.User2//beans运行结果 需要注意的是因为需要解析xml文件数据需要导入对应依赖如下 !-- 用于解析xml文件的包--dependencygroupIdorg.dom4j/groupIdartifactIddom4j/artifactIdversion2.1.3/version/dependencydependencygroupIdjaxen/groupIdartifactIdjaxen/artifactIdversion1.2.0/version/dependency3. Spring之JdbcTemplate JdbcTemplate是Spring提供的一个jdbc模板类是对jdbc的封装。当然现在大多数用的都是MyBatis等。首先需要导入的依赖为 !-- MySQL JDBC 驱动 --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.46/version/dependency !-- spring-jdbc--dependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactId/dependency另外还需要spring-context的依赖哈。因为我这边使用的mysql 数据库版本为5.xxx的版本因此使用mysql的驱动为5.xxx在对应的xml配置文件中的配置为 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean idmyDataSource classcom.lz.demo_spring_24_1.jdbcTemplate.MyDataSourceproperty namedriver valuecom.mysql.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/mytest1?characterEncodingutf8/property nameusername valueroot/property namepassword valueroot//beanbean idjdbcTemplate classorg.springframework.jdbc.core.JdbcTemplateproperty namedataSource refmyDataSource//bean/beans往数据库中插入一条数据如下 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.jdbcTemplate.entity.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class MyJdbcTemplate {Testpublic void test(){ApplicationContext ctx new ClassPathXmlApplicationContext(spring-jdbcTemplate.xml);JdbcTemplate jdbcTemplate ctx.getBean(jdbcTemplate,JdbcTemplate.class);String sql insert into user values(?,?);jdbcTemplate.update(sql,2,王五);} } 插入是可以成功的。 如果想查询数据并且查询出的数据字段都需要映射到对应实体类上对应变量上去可以使用如下代码 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.jdbcTemplate.entity.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class MyJdbcTemplate {Testpublic void test(){ApplicationContext ctx new ClassPathXmlApplicationContext(spring-jdbcTemplate.xml);JdbcTemplate jdbcTemplate ctx.getBean(jdbcTemplate,JdbcTemplate.class);String sql select * from user;ListUser users jdbcTemplate.query(sql,new BeanPropertyRowMapper(User.class));for (User user : users) {System.out.println(user);}} } 如果想要更换成其他的DataSource只需要在xml配置文件中修改对应DataSource的配置即可class属性值修改为druid的driver、url、username、password这四个属性名可能有所不同。。 4. Spring 代理模式 关于Spring aop的功能实现本质上就是动态代理参考文章链接为Spring AOP原理–动态代理。。。关于上述文章的静态代理这里有更加详细的参考代理类和被代理类都需要实现公共的接口如下 公共的接口类 package com.lz.demo_spring_24_1.proxy; // 这是一个接口 public interface IUser {void play();// 方法 play }被代理的类 package com.lz.demo_spring_24_1.proxy.impl;import com.lz.demo_spring_24_1.proxy.IUser;public class IUserImpl implements IUser {Overridepublic void play() {System.out.println(学习编程技术。。。);} } 代理类 package com.lz.demo_spring_24_1.proxy;// 代理类 public class UserProxy implements IUser{// 这里应用泛型可以降低代码的耦合度private IUser iUser null;// 通过构造方法来把对应变量赋值public UserProxy(IUser iUser) {this.iUser iUser;}Overridepublic void play() {System.out.println(这里可以做一些前置操作。。。);iUser.play();System.out.println(这里可以做一些后置操作。。。);} } 测试运行 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.proxy.IUser; import com.lz.demo_spring_24_1.proxy.UserProxy; import com.lz.demo_spring_24_1.proxy.impl.IUserImpl; import org.junit.jupiter.api.Test;public class ProxyTest {Testpublic void test(){IUser iUser new IUserImpl();IUser userProxy new UserProxy(iUser);userProxy.play();} } 但是上述代理存在一个很大的问题那就是接口下面的方法如果很多的话并且在代理类上上的每个方法都需要增强那么被代理类就需要写很多可能较为重复的增强代码而且每个被代理类的都需要编写对应的代理类。因此有了动态代理。。。 4-1. jdk 之动态代理 使用动态代理代理类可以不用编写了但是接口必须要有。。在上述代码基础之上进行操作。。。接口类和被代理类和上面一样。。jdk动态代理不需要额外添加依赖。 Proxy.newProxyInstance(arg1,arg2,arg3)通过上述代码实现一个代理对象其中参数分别表示的意思为 arg1被代理类的类加载器arg2被代理类实现的接口arg3最为关键实现InvocationHandler的对象a且对象a传入参数为被代理的那个对象这样才能实现增强代码这个只需要写一个即可就可以解决上述静态代理存在的那两个问题。 实现InvocationHandler接口的类 package com.lz.demo_spring_24_1.proxy.jdkProxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;public class MyHandler implements InvocationHandler {private Object target;public MyHandler(Object target) {this.target target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// method 为被代理类方法// args 方法参数// 反射。。System.out.println(这里做一些前置操作。。。);Object ans method.invoke(target,args);System.out.println(这里做一些后置操作。。。);return ans;} } 运行代码 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.proxy.IUser; import com.lz.demo_spring_24_1.proxy.UserProxy; import com.lz.demo_spring_24_1.proxy.impl.IUserImpl; import com.lz.demo_spring_24_1.proxy.jdkProxy.MyHandler; import org.junit.jupiter.api.Test;import java.lang.reflect.Proxy;public class ProxyTest {Testpublic void test2(){IUser iUser new IUserImpl();IUser iUserProxy (IUser) Proxy.newProxyInstance(iUser.getClass().getClassLoader(),iUser.getClass().getInterfaces(),new MyHandler(iUser));iUserProxy.play();} } 运行结果和上述一致。。。 4-2. cglib 之动态代理 如果是maven项目需要额外导入cglib的依赖才行。参考代码如下 package com.lz.demo_spring_24_1.proxy.cglibProxy;import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method;public class MyCallback implements MethodInterceptor {Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println(这里可以做一些前置操作。。。);Object ans methodProxy.invokeSuper(target,args);System.out.println(这里可以做一些后置操作。。。);return ans;} } package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.proxy.cglibProxy.MyCallback; import com.lz.demo_spring_24_1.proxy.impl.IUserImpl; import org.junit.jupiter.api.Test; import org.springframework.cglib.proxy.Enhancer;public class ProxyTest {Testpublic void test3(){Enhancer enhancer new Enhancer();// 设置被代理的类enhancer.setSuperclass(IUserImpl.class);enhancer.setCallback(new MyCallback());IUserImpl iUser (IUserImpl) enhancer.create();// 代理的类iUser.play();} }运行结果和上面一致。。 4-3. jdk 与 cglib 动态代理的区别 参考链接在这jdk 与 cglib 动态代理的区别 5. 面向切面编程 AOP 详细请看这篇博文Aop 面向切面编程 Spring 的AOP底层实现本质是动态代理jdk、cglib动态代理两者都有Spring在这两种动态代理中可以根据实际应用场景实现切换如果是代理接口会默认使用jdk动态代理如果要代理某个类这个类没有实现接口那么就会切换到cglib。当然也可以通过配置强制让Spring来使用两者动态代理中的一种。 首先需要导入aspect的依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId /dependency之后编写xml配置文件 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdcontext:component-scan base-packagecom.lz.demo_spring_24_1.proxy.aspect/ !-- 自动扫描--aop:aspectj-autoproxy/ !-- 让 Aspect 起作用-- /beans编写Aspect的切面类 package com.lz.demo_spring_24_1.proxy.aspect;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;Aspect Component public class MyAspect {Before(execution(* com.lz.demo_spring_24_1.proxy.aspect.UserService.*(..)))public void fun1(){System.out.println(前置通知。。。);}}测试代码 package com.lz.demo_spring_24_1;import com.lz.demo_spring_24_1.proxy.aspect.UserService; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyAspectTest {Testpublic void test(){ApplicationContext ctx new ClassPathXmlApplicationContext(spring-2025-aspect.xml);UserService userService ctx.getBean(userService,UserService.class);userService.selectAll();} }运行结果 在这里可以打印一下UserService的Class值可以发现它是属于cglib动态代理生成的。 因为UserService类并不是通过实现某某接口的。 如果想纯注解实现上述效果只需要把上述xml配置文件用一个配置类来代替即可配置类参考如下 package com.lz.demo_spring_24_1.proxy.aspect;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;Configuration ComponentScan(value com.lz.demo_spring_24_1.proxy.aspect) EnableAspectJAutoProxy public class Config { }当然测试代码的加载容器需要修改一下 6. Spring 事务 具体详细请看这篇文章Spring 事务。在一个业务中可能涉及到多条sql数据的执行这些sql数据要么全部执行成功要么全部执行失败为此应用到了事务 Transaction。 事务的四个处理过程包括开启事务、执行核心业务代码、提交事务、回滚事务。事务的四个特性为原子性、一致性、隔离性、持久性也就是常说的ACID其中原子性表示事务不可以再分一致性表示事务要么同时成功要么同时失败隔离性表示事务和事务之间互不干扰持久性表示一旦事务提交它对数据库的修改就是永久性的即使系统发生故障数据也不会丢失。 6-1. 事务的传播特性 关于事务的传播特性总共有7种下述只是给出常见的四种。 测试结果如果外部事物存在并且内部事务也存在且两个事务的传播行为都为REQUIRED。此时内部事务有抛异常的代码在外部事务里边进行了try/catch捕获事务会进行回滚。 如果上述内部事务为REQUIRES_NEW外部事务不变此时外部事务会正常执行内部事务会进行回滚。 6-2. 事务的隔离级别 事务的隔离级别包括读未提交、读已提交、可以重复读、串行化。在上面那篇文章里边只介绍了后3种因为通过设置后面3种隔离级别可以解决对应的问题比如脏读、不可重复读、幻读。 实际测试关于脏读如果其中一个事务a执行查询操作另外一个事务b执行插入操作。如果事务a设置的隔离级别为读未提交b事务没有设置隔离级别数据库是MYSQL也就是隔离级别为读已提交。事务b先执行但是没有结束事务a后执行并已结束此时事务a读取到数据是脏数据也就是脏读。如果事务a设置的隔离级别为读已提交依旧按照上述执行流程来此时事务a的运行结果会报错。 6-3. 事务的超时时间 如果事务设置了超时时间a那么表示超过a秒如果该事务种所有的DML语句还没有执行完毕的话最终结果会选择回滚。事务的超时时间指的事务开始到最后一条DML语句执行完的时间只要不超过这个时间就不会进行回滚操作。如果最后一条DML语句后面还有很多业务逻辑这些业务逻辑执行的时间不计入超时时间。 6-4. 设置事务只读(readOnly) 之所以设置事务为只读是为了提高select语句的执行效率这里启动了Spring的优化策略。在这种事务下只能执行查询操作执行插入、删除、修改操作都会报错。
http://www.ho-use.cn/article/10815450.html

相关文章:

  • 网站视频你懂我意思吧app仙桃哪里做网站
  • 网站建设生存期模型软装设计培训班哪家好
  • 企业建立企业网站有哪些优势?德语网站域名
  • 青岛网站排名优化网站域名包括
  • 深圳如何优化网站免费建站网站群
  • 深圳建站公司开发费用老外做汉字网站
  • 网站建设 ipv6vs2017 asp网站开发
  • 廊坊宣传片制作公司邢台移动网络优化是哪家公司
  • 网站建设业务活动企业网站模板 网页模板
  • 一个人做网站可以做什么华为应用市场下载安装
  • 免费刷推广链接的网站做网站用什么程序
  • 西安市地铁建设指挥部网站怎么做百度推广
  • 惠州做网站公司做微商怎么找客源加人
  • 网站在哪里备案桂城网站建设费用
  • 建设工程造价员网站WordPress文章搜索cpu飙升
  • 中国十大电商做的好的网站北京做视觉网站
  • 自己建设网站服务器云主机可以做网站吗
  • 阿里云建站售前咨询郑州+高端网站建设
  • 长沙精品网站建设公司网络营销推广方法选择
  • 学校网站建设的意见买了域名不备案行吗
  • 公司注册网站源码网站建设需要交文化建设税吗
  • 海珠一站式网站建设简约创意情人节海报设计
  • 企业网站多大空间汉南公司网站建设
  • 公司网站建设如何撤销企业系统建设
  • 做网站做什么公司好旅行社营业网点可以做网站吗
  • 鲜花网站建设的主要工作流程北京市官方网站
  • google adwords建站优化易下拉系统
  • 网站建设有没有做的必要性交互式网站是什么
  • 营销型网站建设市场美工培训电商设计培训班
  • 科创纵横 网站建设搜狗推广后台登录