spring学习

2021-08-01 13:56

阅读:895

标签:pointer   字符   out   持久层   int   起点   容器   循环   struct   //把创建的对象都放到applicationContext容器中,要用时,在通过id一个一个取出来   壹、第一个spring项目 主配置文件     //在spring中,每一个java对象对应一个标签,即一个标签代表一个java对象 //id:对象的自定义名称,唯一值,spring通过这个名称找到该对象 //class:类的全限定名称(不能是接口,spring通过反射机制创建对象) //spring把创建好的对象放到map集合中,集合的key就是上面的id值,value是创建的对象 //spring创建对象默认调用无参构造方法   测试程序 String config="beans.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(config);       (2)?Object object=ac.getBean("a");     //此时对象已经创建好了,通过id,从容器中获取相对应的对象SomeService service=(SomeService)object;service.doSome(); //只要是配置文件,都是从target/classes的根目录为起点开始找的 //ApplicationContext就是spring的容器,在创建spring容器时,会创建配置文件中的所有java对象,也就是在(2)步时,先创建容器,再创建java对象 //ClassPathXmlApplicationContext(config):表示从类路径(即target/classes目录)中加载spring的配置文件; FileSystemXmlApplicationContext():表示从本地磁盘中加载spring的配置文件,不常用   贰、常用的方法 获取容器中定义的对象数量 int nums=ac.getBeanDefinitionCount();System.out.println(nums);   获取容器中定义的对象名称 String[] names=ac.getBeanDefinitionNames();for (String n:names){   System.out.println(n);         //a}     叁、基于XML的DI //在spring的配置文件中,使用标签和属性完成赋值,叫做基于XML的DI实现   一、set注入 //set方法的执行是在构造方法之后执行的   简单注入         //name="属性名字",value="赋给属性的值" //com.dh.bao.Student类中所赋值的属性必须有set()方法,没有就报错;有set(),但里面没有this.age = age;赋值语句,不报错,只是该属性不能被赋值,为null //spring只关心有没有对应的set()方法,即使只有set()方法,没有属性,系统也会正常运行 //若在set()方法中有System.out.println(123);语句,该语句也会正常运行,输出123   引用类型注入        ?             //com.dh.bao.School类中有Student属性,使用ref属性完成赋值 //两个标签的位置没有规定,谁在上方都可以。因为在第一次因位置没加载到时,会进行二次扫描     二、构造注入 //通过有参构造方法赋值               三、引用类型的自动注入 byName        ?         //student的中的id值必须和com.dh.bao.School类中的Student类型的引用名称相同 //在School的中添加autowire="byName"属性   byType //同源关系 java类中引用属性的数据类型和该引用属性相关的中的class是一样的 java类中引用属性的数据类型和该引用属性相关的中的class是父子关系 java类中引用属性的数据类型和该引用属性相关的中的class是接口与实现类关系                 //在spring的配置文件中也是由上而下逐行执行 //当执行到School的标签时,先创建school对象,然后再给其简单属性赋值。最后执行autowire="byType"语句;扫描整个spring配置文件,找与School对象的属性student同源的,即student的子类,student类本身,若student是接口,其实现类也行。找到之后赋值即可 //注意:在使用byType时,同时只能有一个符合条件,当有多个标签符合条件时,系统报错       肆、基于注解的DI   一、创建对象 Component注解 @Component(value="myStudent")public class Student {    private String name;    private int age;   ...}         //当只有value一个属性时,value可以省略不写;也可以不指定对象的名称,Spring默认提供类名首字母小写为对象名称   配置文件中设置组件扫描器     //spring会扫描base-package属性指定的包和其子包中所有的类,找到类中的注解,按照注解的功能创建对象或者赋值     二、多注解的分层 @Repository:用在持久层上,放在dao的实现类上,创建dao对象 @Service:用在业务层上,创建service对象,可以有事务等功能 @Controller:用在界面层上,创建控制器对象 //以上3个注解的使用语法与@Component一样,都能创建对象,但这3个注解还有其他的额外功能 //当某个类不属于以上3种情况时,才用@Component创建对象     三、简单类型赋值 @Component(value="myStudent")public class Student {    @Value(value = "zs")    private String name;    @Value(value="29")    private int age;   ...}     //属性value是String类型 //@Value注解可以出现在属性的定义上(推荐),也可以出现在set()方法上 //@Value注解是通过反射机制赋值的,所以该类可以没有set()方法     四、引用类型赋值   @Autowired注解 @Component(value="mySchool")public class School {   @Value("donghua")   private String name;   @Value("shanghai")   private String address;   @Autowired   private Student student;   ...}?@Component(value="myStudent")public class Student {   @Value(value = "zs")   private String name;   @Value(value="29")   private int age;   ...}   //@Autowired注解默认采用的是byType的方式自动注入 //只要通过组件扫描器扫描的包中有student属性对应的同源的关系的类就能完成该引用属性的赋值;或者spring配置文件有通过标签完成对该引用同源关系的类赋值的,也是可以的。即两种方式可以混用,即xml与注解 //@Autowired注解可以出现在属性的定义上(推荐),也可以出现在set()方法上。其是通过反射机制赋值,所以该类可以没有set()方法   1. byName(@Qualifier) @Component(value="mySchool")public class School {    @Value("donghua")    private String name;    @Value("shanghai")    private String address;        @Autowired    @Qualifier(value="aa")         //@Qualifier注解    private Student student;   ...}?@Component(value="aa")public class Student {    @Value(value = "zs")    private String name;    @Value(value="29")    private int age;   ...}   //使用@Qualifier注解指定赋值的类的id值   2. required属性 @Autowired(required = true) //required = true:表示引用类型赋值失败时,程序报错,并终止接下来的程序 (默认) //required = false:表示引用类型赋值失败时,程序正常执行,引用属性的值为null     @Resource注解 @Component(value="mySchool")public class School {    @Value("donghua")    private String name;    @Value("shanghai")    private String address;        @Resource    private Student student;   ...}         //@Resource注解来自jdk中,但spring框架支持该注解的功能,用法与@Autowired注解相似 //@Resource注解默认采用byName的方式,其先使用byName的方式进行赋值,若赋值失败,则采用byType的方式再次尝试 //若只想使用byName的方式,则需添加属性name:@Resource(name="aa") //@Resource注解可以出现在属性的定义上(推荐),也可以出现在set()方法上。其是通过反射机制赋值,所以该类可以没有set()方法       伍、多个配置文件 //在resources/bao目录下有spring-1,spring-2,spring-3,3个配置文件 //在spring-1中添加             //classpath与target/classes是等价的 //添加以上内容之后,spring-1就是主配置文件了,在测试程序中,只用加载spring-1,其他两个配置文件就会自动加载 //可以使用通配符“ * ” //这样就可以一次将spring-2,spring-3都导入。但要注意,在通配符表示的范围中不能包含主配置文件spring-1,不然会陷入死循环,一直加载。可以通过给主配置文件改名或者修改目录,不在同一目录下       陆、AOP //aop (Aspect Orient Programming) :面向切面编程。切面:给目标类增加的功能,就是切面 //aop的底层是基于动态代理的,它的的本质就是动态代理的规范化,是一个标准 //spring内部实现了aop规范,但其主要用于事务的处理。我们主要用一个专门做aop的框架:aspectJ //所以aop支持jdk代理和cglib代理   一、切面表达式 execution (访问权限 方法的返回类型 方法的声明(参数) 异常) //方法的返回类型,方法的声明(参数)这两项是必须要写的,其他两项可以省略不写 //每一部分之间用空格隔开 //切入表达式中可以用以下符号 *:0至多个字符 ..:用在方法参数中,表示任意多个参数;用在包名后,表示当前包及其子包的路径 +:用在类名后,表示当前类及其子类;用在接口后,表示当前接口及其实现类 //例子:excution(* set*(..)) :表示以set三个字母开头的任意方法     二、第一个例子 创建接口及目标类 package com.dh.bao;?public interface SomeService {    void doSome(String name, Integer age);}?public class SomeServiceImpl implements SomeService{           //目标类    public void doSome(String name, Integer age) {                  System.out.println("abc");   }}   创建切面类,切面表达式指向目标类 @Aspectpublic class MyAspect {   @Before(value = "execution(public void com.dh.bao.SomeServiceImpl.doSome(String,Integer))")   public void MyBefore(){       System.out.println("切面:" + new Date());   }}   声明目标及切面对象,还有声明自动代理生成器        ?         //自动代理生成器 //程序执行到 时,会扫描整个spring的配置文件中所有的类及对象,找到@Aspect及相关注解,将切面类指向的目标类转化为代理类   测试程序 String confg="applicationContext.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(confg);SomeService ss=(SomeService)ac.getBean("someservice");   //这里强转的是接口,而不是接口的实现类SomeServiceImpls.doSome("zs",20);     ?//切面:Thu Jun 24 10:59:54 CST 2021  abc                                           //注意:此时ss对象的类型不是SomeService类,而是com.sun.proxy.$Proxy6类型 //若切面表达式写错了,程序依然会正常运行,不会报错;只是ss对象就不是代理类型,而是SomeService类型。原因是切面表达式不对,导致指定目标类错误,找不到目标类,也就无法完成转换   三、注解 @Aspect注解 //作用是:表明当前类为切面类 //位置:定义在类上   @Pointcut注解 //定义和管理切入点,若项目中有多个切入点表达式是重复的,则可以使用该注解,达到复用的目的 属性:value值(切入点表达式) 位置:在方法上 特点:当使用@Pointcut注解定义在一个方法上时,这个方法的名称就是切入表达式的别名。在其他的通知注解中,value属性的值就可以使用这个别名,代替切入点表达式 @Pointcut(value = "execution(public Integer com.dh.arround.MyArroundImpl.doSome())")public void www(){   //无需写代码} //注意:在其他通知注解中,value="www()",而不是value="www"。是要包含括号的       四、通知 //切面类相对于目标类执行的时间,在aop规范中称为Advice,也就是通知。   JoinPoint参数 //指定通知方法中的参数,即切面方法中的参数;所有通知方法都可以有这个参数 //通知方法:被通知注解(@Before,@After,@AfterReturning等)修饰的方法 public class MyAspect {    @Before(value = "execution(public void com.dh.bao.SomeServiceImpl.doSome(String,Integer))")    public void MyBefore(JoinPoint jp){        System.out.println("目标方法的签名:" + jp.getSignature());        System.out.println("目标方法的名称" + jp.getSignature().getName());                Object args[]=jp.getArgs();       //获取目标方法的实参       ...}         //目标方法的签名:void com.dh.bao.SomeServiceImpl.doSome(String,Integer)   @Before (前置通知注解) 属性:value值(切入点表达式) 位置:在方法上 特点:在目标类的方法之前执行;不改变目标方法的执行结果;不影响目标方法的执行 对切面方法的要求:要是public;要是void;方法名称自定义;方法若有参数,不能自定义,从几个参数类型中选择   @AfterReturning (后置通知) 属性:value值(切入点表达式); returning:自定义变量,表示目标方法的返回值(自定义的变量名必须和通知(切面)方法的形参名一样) 位置:在方法上 特点:在目标类的方法之后执行; 能够获取到目标方法的返回值,可以在切面方法中处理这个返回值 不能改变目标方法的返回值在最后的输出 对切面方法的要求:要是public;要是void;方法名称自定义;方法有参数,推荐Object类型 public class AfterImpl implements After{    public Integer doSome() {        return 100;   }}?public class AfterAspect {    @AfterReturning(value = "execution(public Integer com.dh.After.AfterImpl.doSome())",returning = "bbb")    public void myAfter(Object bbb){                    System.out.println("切面:" + bbbb);    //由获取的返回值可以输出一些额外的功能,但不能改变目标返回值的最后输出        bbb=200;   }}?After after=(After)ac.getBean("afterimpl");Integer in=after.doSome();System.out.println(in);            //100,并没有变成200     @Around (环绕通知注解) 属性:value值(切入点表达式) 位置:在方法上 特点: 在目标类的方法前后都能执行 能控制目标方法是否被调用执行 修改原来目标方法的执行结果,影响最后的调用结果 对切面方法的要求: public; 必须有一个返回值,推荐使用Object; 方法名称自定义; 方法有参数,固定参数:ProceedingJoinPoint;其是JoinPoint接口的子接口,所以它能用JoinPoint中的所有方法 public class MyArroundImpl implements MyArround{    public Integer doSome() {        System.out.println("目标");        return 1;   }}?public class MyArroundAspect {    @Around(value = "execution(public Integer com.dh.arround.MyArroundImpl.doSome())")    public Object myArround(ProceedingJoinPoint pjp) throws Throwable {        Object result=null;        System.out.println("目标前");           (1)        result=pjp.proceed();                   (2)        System.out.println("目标后");           (3)        return result;   }} //可在(1)处添加pjp.getArgs()方法,获取目标方法的实参,可修改实参,也可通过实参判断是否继续执行目标方法,即(2) //(2)为执行目标方法,获取目标方法的返回值 //在(3)处可对目标方法的返回值进行修改,这是会影响最后在测试程序中的输出结果的。与@AfterReturning中的不同     @AfterThrowing (异常通知) 属性:value值(切入点表达式); throwing:自定义变量,表示目标方法抛出的异常(自定义的变量名必须和通知(切面)方法的形参名一样) 位置:在方法上 特点:在目标类方法抛出异常时执行; 可以做异常的监控程序,监控目标方法执行时是不是有异常 对切面方法的要求:要是public;要是void;方法名称自定义;参数只有一个:Exception,若还有就是JoinPoint //常用的方法: System.out.println(ex.getMessage());  //打印异常信息     @After (最终通知注解) 属性:value值(切入点表达式) 位置:在方法上 特点:在目标方法之后执行 总是会执行,即使目标方法出现异常,也会执行(相当于try...catch中的finally) 所以一般用来做资源的关闭,清理工作 对切面方法的要求:要是public;要是void;方法名称自定义;方法没有参数,若有就是JoinPoint     五、cglib动态代理 //若目标类有接口时,使用的jdk代理。被转换的目标类的类型是:com.sun.proxy.$Proxy6 //若目标程序没有接口,spring框架就自动使用cglib代理,不需要程序员操作;被转换的目标类的类型是: com.dh.arround.MyArroundImpl$$EnhancerBySpringCGLIB$$8fc79603   //若目标类有接口,但你希望用cglib代理,则将自动代理生成器改为:   //使用cglib代理的前提是:目标类能被继承       柒、spring与mybatis整合   spring配置文件分析                ?         //通过连接数据源aaa和连接mybatis配置文件,在内部先创建SqlSessionFactory对象,然后再由该对象创建SqlSession对象 //因为是标签,则com.alibaba.druid.pool.DruidDataSource类中一定有url属性对应的set()方法,因为该标签是通过set注入完成赋值的           //MapperScannerConfigurer类会在内部调用getMapper()方法,生成每个dao接口的代理对象 //MapperScannerConfigurer会扫描basePackage指定的包中所有的接口,把每个接口都执行一次getMapper()方法,得到每个接口的dao对象,再把创建好的dao对象放进spring容器中 //dao对象的默认名称:接口名首字母小写       //此时给StudentServiceImpl类中的studentDao属性赋值的就是上面那步生成的dao对象     测试程序分析 String conf="applicationContext.xml";ApplicationContext ac=new ClassPathXmlApplicationContext(conf);StudentService ss=(StudentService)ac.getBean("ccc");?Student student=new Student();student.setId(7);student.setName("gg");student.setAge(44);student.setSex(0);int nums=ss.addStudent(student);List list=ss.queryStudent();for(Student stu:list){   System.out.println(stu);} //注意:此时的ss对象是com.dh.service.impl.StudentServiceImpl,而不是com.sun.proxy.$Proxy类型,在aop中才是 //spring与mybatis整合中常通过在service中声明dao对象,并给其赋值,再用其在service类中调用dao接口中的方法;而不是直接使用dao对象调用dao接口中的方法,中间要转一下 //spring与mybatis整合在一起使用时,事务是自动提交的,无需手动写SqlSession.commit()       捌、spring中的事务 //不同的数据库访问技术处理事务的方式不同,比如:jdbc(conn.commit())与mybatis(SqlSession.commit())处理事务的方式就不同,所以spring就提供了一种事务处理的统一模型,能用统一的步骤,方式完成多种不同数据库访问技术的事务处理   一、事务管理器 //即PlatformTransactionManager接口,封装了commit,rollback等方法 //该接口为每一种数据访问技术都设置好了专门的实现类,比如mybatis对应的实现类是DataSourceTransactionManager   二、事务定义接口 //即TransactionDefinition接口 //该接口中定义了事务描述相关的三类常量:事务的隔离级别,事务的传播行为,事务默认的超时时限   事务的隔离级别 隔离级别含义ISOLATION_DEFAULT 默认, 使用后端数据库默认的隔离级别 ISOLATION_READ_UNCOMMITTED 读未提交, 允许读取尚未提交的更改。可能导致脏读、幻读或不可重复读。 ISOLATION_READ_COMMITTED 读已提交,允许从已经提交的并发事务读取。可防止脏读,但幻读和不可重复读仍可能会发生。(Oracle 默认级别) ISOLATION_REPEATABLE_READ 可重复读, 对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可能发生。(MYSQL默认级别) ISOLATION_SERIALIZABLE 串行化, 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。     事务的传播行为 //只用掌握前面3种传播行为即可 传播行为含义PROPAGATION_REQUIRED 指定的方法必须在事务内运行。若当前存在事务,就加入到当前事务中;若当前没有事务,则创建一个新的事务。这是spring默认的传播行为 PROPAGATION_SUPPORTS 表示指定的当前方法可以在没有事务上下文中执行;但是如果存在当前事务的话,那么该方法会在这个事务中运行。查询操作就属于这种行为 PROPAGATION_REQUIRES_NEW 指定的方法总是会新建一个事务,并在新建的事务中执行,若当前存在事务,则将当前事务挂起(即暂停,包括事务中所有的方法也暂停),直到新事务执行完毕 //PROPAGATION_REQUIRED实例解释:PROPAGATION_REQUIRED传播行为指定方法a,若B事务中的b方法调用方法a,则a方法加入到B事务中执行;若没有事务的b方法调用a方法。则a方法自己新建一个事务c,在事务c中执行   传播行为含义PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 PROPAGATION_NOT_SUPPORTED 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager PROPAGATION_NEVER 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务       事务默认的超时时限 //为了避免一个事务长时间占有资源,所以设置了超时时间 //表示一个方法或事务的最长执行时间,如果方法执行时间超过了这个超时时限,事务就会回滚。单位是:秒,整数值,默认值为:-1     三、提交事务与回滚事务时机 //当你的业务方法,执行成功,没有异常抛出,spring会在方法执行完毕,自动调用事务管理器中的commit方法,提交事务 //在默认设置下,事务只在出现运行时异常(Runtimeexception及其子类)或者错误(Error)时回滚事务,而在出现非运行异常时,主要是受检查异常(checked exception)时不回滚,自动调用事务管理器中的commit方法提交事务。 //不过可以人为设置,主动声明在出现特定受检查异常时像运行时异常一样回滚。同样,也可以声明一个事务在出现特定的异常时不回滚,即使特定的异常是运行时异常。       四、事务处理方案   @Transactional注解 //适用于中小型项目 //该注解使用的是spring框架中内部的aop来处理事务 //@Transactional注解只能用于public方法,用在非public方法时,Spring虽然不会报错,但不会将该方法纳入该事物中,因为spring会忽略所有非public方法上的@Transactional注解   属性 propagation:事务传播行为设置,该属性类型为Propagation枚举(7个),默认值为:Propagation_REQUIRED isolation:事务隔离级别设置,该属性类型为Isolation枚举(5个),默认值为Isolation_DEFAULT readOnly:设置目标方法对数据库的操作是否只能读事务,而不能读写事务。该属性为boolean,默认读写,即为false timeout:事务超时时间设置。单位:秒,类型为:int,默认值为:-1,即没有时限 rollbackFor:指定需要回滚的异常类(即出现该指定异常类后,该事物回滚,即使该异常属于非运行时异常)。类型为Class[],默认值为空数组,当只有一个异常类时,可以不使用数组。 rollbackForClassName:指定需要回滚的异常类的类名,类型为String[],默认值为空数组,当只有一个异常类时,可以不使用数组。 noRollbackFor:指定不需要回滚的异常类(即出现该指定异常类后,该事物不回滚,即使该异常属于运行时异常)。类型为Class[],默认值为空数组,当只有一个异常类时,可以不使用数组。 noRollbackForClassName:指定不需要回滚的异常类的类名,类型为String[],默认值为空数组,当只有一个异常类时,可以不使用数组。 value :可选的限定描述符,指定使用的事务管理器   底层原理 //spring使用aop机制,创建该注解所在类的代理对象,给方法加入事务功能。使用了环绕通知的方式,在目标业务方法执行之前,在切面方法中开启事务,在业务方法结束之后,提交事务,或者出现异常时,回滚事务,这一切都有spring框架自动控制。   使用步骤 @Transactional(propagation = Propagation.REQUIRED,                   isolation = Isolation.DEFAULT,      //这些配置都是默认的,可以不写这些属性,直接@Transactional在方法上               readOnly = false               ......)public void buy(Integer goodsId, Integer nums) {   ...}         //声明事务管理器并注册,是对数据源声明事物管理器 //ref属性:其值为数据源的id值,在这里是阿里的那个数据源 //:是对事务管理器进行注册,创建代理对象     aspectj //适合大型项目 //使用aspectj框架功能在spring的配置文件中声明类,方法的事务。这种方式业务方法与事务配置是完全分离的 //使用该方式需要在提前加入aspectj的依赖   声明事务管理器       声明业务方法的业务属性                 //name:方法名称(不包含包名和类名),可以使用完整方法名,也可以用通配符 “*” 。当你需要给成千上万的方法配置事务时,你可以给同一类的方法命名时有共同点,比如:以字母abc开头,则在name属性处填:abc*,就能给这一类的方法添加事务;当name=“*”,表示给目标类中所有方法都添加该事物 //当有一方法同时满足完整方法名,带有*的方法名,以及只有*,即这三种情况同时存在时,spring会先匹配完成方法名,当匹配成功后,就不再匹配其他的;只有匹配失败,再去带有*的方法名中找,前两者都没匹配成功,才执行只有*的事务配置   配置aop         //:配置切入点表达式,指定哪些包中的类需要使用业务(即目标业务方法所在的包名,类名) //:配置增强器,关联advice和pointcut(连接目标类和业务方法)spring学习标签:pointer   字符   out   持久层   int   起点   容器   循环   struct   原文地址:https://www.cnblogs.com/zhestudy-2021/p/14961117.html

上一篇:window.name

下一篇:Jmeter之HTTP请求默认值


评论


亲,登录后才可以留言!