尧图精选

Spring进阶

🕒 发布时间:2026/10/1 9:49:38 📁 来源:尧图网络
1.Spring容器定义组件/Bean具有一定功能的对象有名字类型对象作用域组件一定被交给IOC容器管理组件注册到IOC容器中组件本身是一个普通类加上注解后被托管给IOC容器容器管理组件IOC控制资源的控制权IOC里的组件是单例的反转代理DI依赖组件的依赖关系注入自动注入自动赋值注册注解①bean用于方法级别的注解作用是将方法返回的对象注册到IOC容器中组件默认的id就是方法名默认是单实例的,bean(重命名)bean方法所在的类必须有相关注解才能被扫描到获取IOC容器中的组件//1.根据组件类型获取容器中的组件该类型组件存在且唯一否则报错 Person person ioc.getBean( Person.class); System.out.println(person); //2.根据组件类型获取所有组件 MapString, Person typeioc.getBeansOfType(Person.class); System.out.println(type); //3.按照组件名字获取组件 Person person1(Person) ioc.getBean(ABC); System.out.println(person);注册组件Bean(ABC) public Person zhangSan(){ Person person new Person(); person.setName(张三); person.setAge(18); person.setGender(男); return person; }②Configuration告诉IOC容器这是一个配置类确保组件的单实例化,配置类也是容器中的组件③Component标记在类上该类会被注册到IOC容器中注解对应层级职责岗位描述Controller表现层 (Presentation Layer)负责接收 HTTP 请求解析参数调用业务逻辑最后返回响应JSON 或 页面。Service业务逻辑层 (Business Layer)负责核心业务规则、计算、事务控制。它调用 DAO 层处理数据后返回给 Controller。Repository数据访问层 (Data Access Layer)负责与数据库交互进行增删改查CRUD。分层注解能起作用的前提是都在主程序所在的包里面④ComponentScanbasepakage“包”标记在主程序中主程序扫描对应包下的注解类并注册到IOC容器中不推荐包范围过大要扫描很多文件⑤Import类型.class一般用于把外部类放在IOC容器中标记位置随便推荐放在专门的配置类上⑥Scope“作用域”一般用于组件类和方法上来说明这个组件的作用域作用域说明应用场景singleton默认大多数容器内同名称的bean只有一个实例单例默认会在项目启动时创建对象不管是否会被调用可在该类上加入Lazy注解来延迟到调用该类时再创建bean对象对于无状态的bean即不保存数据只调用一些方法prototype每次使用该bean时会创建新的实例非单例在类上加入Scope“prototype”注解可实现该作用有状态的beanrequest每个请求范围内会创建新的实例web环境中了解session每个会话范围内会创建新的实例web环境中了解⑦Lazy一般用于单实例下放在组件上在组件被调用时才会被创建和加载⑧FactoryBean接口 了解如果制造某些对象比较复杂这个组件的类型是泛型中填写的类型Car组件的名称是工厂的名称ByDFactorypublic class ByDFactory implements FactoryBeanCar { // 调用该方法给容器注册一个组件 Override public Nullable Car getObject() throws Exception { Car carnew Car(); return car; } // 说明该组件类型 Override public Nullable Class? getObjectType() { return Car.class; } // 是单例吗 Override public boolean isSingleton() { return true; } }⑨Conditional实现Condition接口的Class对象满足某个条件的组件才能被注册到IOC容器中派生注解ConditionalOnClass判断环境中有对应字节码文件才注册bean到IOC容器。ConditionalOnMissingBean判断环境中没有对应的bean(类型或名称)才注册bean到IOC容器。ConditionalOnProperty判断配置文件中有对应属性和值才注册bean到IOC容器。注入注解①Autowired寻找方式1.按照类型寻找容器里只有一个类型名字无所谓2.有多个可以将变量名设置为组件名// 有多个可以放在集合中集合的key是bean的id Autowired ListPerson personList; Autowired MapString,Person personMap;②primaryqualifier“名字”对于该类型有多个组件,在一个组件上加上primary注解则被设置为默认组件默认调用该组件名字不会被考虑如果有默认组件的情况下想调用别的组件在调用时加上qualifier注解来指定要调用的组件③Resource是javaee包下的通用性更强功能和Autowired差不多根据名称来寻找组件④构造器注入Setter方法注入对于Component类在被放置到IOC容器时要实现构造方法来创建完整的对象这时候IOC容器会优先从自己容器中寻找合适的组件注入这就是构造器注入在创建对象时实现官方推荐安全Repository public class UserDao { Car car; public UserDao(Car car){ this.carcar; } }同样通过Set方法来实现上述功能在创建对象完成后实现一般要加上Autowired注解这样IOC容器会自动调用Set方法完成初始化⑤感知接口组件继承该接口的子接口spring容器会自动注入这些资源⑥ValueValue注解主要用于将外部配置的值注入到 Spring 管理的 Bean 的字段、方法参数或构造函数参数public class Dog { // 直接赋值 Value(xiaogou) private String name; // 可以获取配置文件中的值 Value(${dog.age}) private Integer age; // 直接写SPEL表达式来获取值 Value(#{T(java.util.UUID).randomUUID().toString()}}) private String color; public Dog(){ System.out.println(Dog构造器。。。); }⑦PropertySource当配置文件不是系统默认的文件可通过该注解将这个配置文件放到容器中//把该配置文件添加到容器中位置无所谓 //在自己的项目下寻找配置类 PropertySource(classpath:cat.properties) //PropertySource(classpath*:cat.properties)在所有包寻找配置类 Data Component public class Cat { Value(${cat.name:Jerry}) private String name; Value(${cat.age:6}) private Integer age; }⑧profile“环境标识可以写多个”和Condition的作用相似就是为了特定条件下使用对应组件1.定义环境标识如果不定义会有默认标识default2.在配置类上定义所要激活的环境组件生命周期属性注入完成才说明初始化成功1.Bean(initMethod initUsr ,destroyMethod destroyUsr)在bean注解中会有一些属性就是在组件某个生命周期中去实现某个方法2.3.这是两个接口让组件去实现4.5.这是两个注解写在组件类中的方法上6.具有拦截和修改功能这是一个接口实现类会对所有的组件进行拦截实现类放在单独的包下2.springAOP静态代理是在编码期间确定好的关系代理对象是把目标对象当做自己的属性在实现目标对象的同时增加额外的功能静态范围太小可以动态代理动态代理运行期间实现代理关系本质是拦截目标对象在运行被拦截并实现对应操作可以拦截所有对象不好编写下面是一个例子Test void contextLoads() { //1.定义目标对象 MathCalculator target new MathCalculatorImpl(); //2.定义拦截器new InvocationHandler()类似于一个拦截器proxy是代理对象method是目标对象方法args是目标对象方法参数 InvocationHandler hnew InvocationHandler() { //这是匿名内部类实现拦截器接口拦截目标对象方法 Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(canshu Arrays.asList(args)); args[0]1; System.out.println(改后参数Arrays.asList(args)); //这行代码的作用是调用目标对象方法 Object resultmethod.invoke(target,args); return result; } }; //3.定义代理对象实现动态代理,getClassLoader()是得到目标对象类加载器getInterfaces()是得到目标对象接口 //Proxy是一个静态类newProxyInstance()是创建代理对象里面传递参数是类加载器接口调用方法 MathCalculator proxy(MathCalculator) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), h); proxy.add(1,2); }当把代理对象单独拿出来创建就可以实现所有目标对象的动态代理把记录日志摘出实现解耦缺点目标对象必须要有接口否则会报错AOP面向切面编程实现步骤导入AOP依赖aspectj4.0版本后依赖改名了编写切面aspect写通知方法切入点表达式Component Aspect public class LogAspect { Before(execution(int *(int,int))) public void logStart(){ System.out.println(日志开始记录); } After(execution(int *(int,int))) public void logEnd(){ System.out.println(日志结束记录); } AfterThrowing(execution(int *(int,int))) public void logException(){ System.out.println(日志异常抛出); } AfterReturning(execution(int *(int,int))) public void logReturn(){ System.out.println(日志返回); } }测试直接调用切入方法jvm会自动识别并拦截切入点表达式args方法的参数a如果b是a的子类则也能匹配上Args(参数的注解)这个是关注方法上有没有注解PointCut“公共的路径”其他注解可以直接调用这个方法public class LogAspect { Pointcut(execution(int *(int,int))) public void pointCut(){ } Before(pointCut()) public void logStart(JoinPoint joinPoint){ System.out.println(joinPoint.getSignature()Signature); }方法的参数值前提通知方法不知道连接点信息且传递进的参数不能随意设置。①Joinpoint// result的值的传递是spring框架根据注解中的returning属性来判断的 AfterReturning(value execution(int *(int,int)),returning result) public void logReturn(JoinPoint joinPoint, Object result){ MethodSignature signature (MethodSignature) joinPoint.getSignature(); String namesignature.getName(); System.out.println(name方法返回结果是:result); }多切面类名字母越小越在外边可以用注解Order数字来确定顺序在获取异常时要把异常抛出让外边的切面也能感知到异常细节增强器:增强器链切面的所有通知方法都是增强器他们被组织成链路放到集合中目标方法真正执行前后会去增强器链中执行通知方法。AOP实现逻辑创建代理对象----设置增强器链-----调用通知方法源码56,57节雷神ssmAround/* 环绕通知固定写法 object:返回值 proceedingJoinPoint:连接点对象 */ Around(execution(int *(int,int))) public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println(环绕通知); //得到参数可以修改再传入目标对象 Object[] args joinPoint.getArgs(); Object proceednull; try { proceedjoinPoint.proceed(args); System.out.println(返回通知proceed); } catch (Throwable e) { System.out.println(异常通知e.getMessage()); } finally { System.out.println(后置通知); } //可以修改返回值 return proceed; } }3.spring声明式事务声明式代码量小封装太多排错难实现底层事务管理器进行事务的提交或回滚事务拦截器:管理事务控制事务提交或回滚的时机transactional的属性1.timeout#{int}s超时是从事务的开始到最后一个dao层方法结束的时长超时后事务会回滚2.readOnlytrue 只读3.隔离级别对于读写并发问题补充1.对于service通常注入容器的是实现类调用的是接口这是为了防止实现类经常改变引起大量修改。2.AnnotationUtilsClassUtilstypeutilsreflectutils包中可以查询注解或类的信息CtrlN查询类3.声明式或编程式声明式通过注解告诉框架自己要做什么实现靠框架完成编程式自己通过编程实现对应功能4.idea中数据库连接idea中右侧的数据库是idea database工具可以实现和datagrip一样的功能Springboot中配置数据库再连接数据库是相当于idea识别这个数据库通过这个工具又连接了数据库5.构造器注入和字段注入的区别字段注入是先注册组件的基本信息再根据注入构造组件然后再new空对象再把组件地址赋值给空对象1. Spring 开始处理 UserServiceImpl 的创建。2. Spring 立即扫描 UserServiceImpl 的所有 Autowired发现需要 UserDao。3. Spring 立刻递归调用 getBean(UserDao.class)a. 创建 UserDao 之前先扫描发现需要 DataSource。b. 递归调用 getBean(DataSource.class)- DataSource 没有依赖直接 new 出来完整对象。c. DataSource 造好了回传给 UserDao。d. 现在 UserDao 依赖齐全调用构造器 new UserDao(DataSource) 出来完整对象。4. UserDao 造好了回传给 UserServiceImpl。5. 现在 UserServiceImpl 的依赖齐全调用无参构造器 new UserServiceImpl()。6. 紧接着Spring 通过反射将 UserDao 的地址塞进 UserServiceImpl 的空壳里。构造器注入直接new一个有参对象在构造时直接把相关参数传递进去安全
上一篇/下一篇内容由系统自动关联 返回资讯列表 →