标签: Spring

spring的Bean初始化方法的2种方式

环境 jdk1.8、springboot、idea

 

代码案例

  • 【方式一】实现接口方式InitializingBean

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • 【方式二】通过xml配置方式<bean init-method=”myInit” /bean>

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • 运行结果

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

spring源码分析

  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactoryinvokeInitMethods方法 【自己可以找下】

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • 注意这里是直接通过Bean的方法去调用afterPropertiesSet

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • 这里是<bean init-method=”myInit” /bean>执行的地方

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • 下面是debug的信息

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • 通过反射java.lang.reflect.Method的invoke方法去执行

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

  • DisposableBean和 destroy-method=”myDestroy” 的源码
  • 也是一个Bean方法直接调用,一个反射destroy-method

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

面试官:说下spring的Bean初始化方法的2种方式 程序员:不知道

 

总结

  • Spring 2种Bean初始方法的执行方式,可以同时执行,接口方式InitializingBean先执行,配置init-method方式后执行,详情请见spring源码
  • 执行效率分析,接口InitializingBean方式比 通过反射配置init-method方式快。
  • 其他特性请debug进去自己看看,源码还是要看看的。

spring注解-@Transactional事务几点注意

这里面有几点需要大家留意:
A. 一个功能是否要事务,必须纳入设计、编码考虑。不能仅仅完成了基本功能就ok。
B. 如果加了事务,必须做好开发环境测试(测试环境也尽量触发异常、测试回滚),确保事务生效。
C. 以下列了事务使用过程的注意事项,请大家留意。
1. 不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
2.不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。
3.使用了@Transactional的方法,对同一个类里面的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。(经常在这里出错)
4.使用了@Transactional的方法,只能是public,@Transactional注解的方法都是被外部其他类调用才有效,故只能是public。道理和上面的有关联。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但事务无效。
5.经过在ICORE-CLAIM中测试,效果如下:
A.抛出受查异常XXXException,事务会回滚。
B.抛出运行时异常NullPointerException,事务会回滚。
C.Quartz中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
D.异步任务中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
E.在action中加上@Transactional,不会回滚。切记不要在action中加上事务。
F.在service中加上@Transactional,如果是action直接调该方法,会回滚,如果是间接调,不会回滚。(即上文3提到的)
G.在service中的private加上@Transactional,事务不会回滚。

spring事务@Transactional在同一个类中的方法调用不生效

spring提供了非常强大的事务管理机制,之前一直以为只要在想要加注解的方法上加个@Transactional注解就万事大吉了

%title插图%num

但是今天发现这样做在某些情况下会有bug,导致事务无法生效。

当这个方法被同一个类调用的时候,spring无法将这个方法加到事务管理中。

我们来看一下生效时候和不生效时候调用堆栈日志的对比。

%title插图%num

通过对比两个调用堆栈可以看出,spring的@Transactional事务生效的一个前提是进行方法调用前经过拦截器TransactionInterceptor,也就是说只有通过TransactionInterceptor拦截器的方法才会被加入到spring事务管理中,查看spring源码可以看到,在AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice方法中会从调用方法中获取@Transactional注解,如果有该注解,则启用事务,否则不启用。

%title插图%num

这个方法是通过spring的AOP类CglibAopProxy的内部类DynamicAdvisedInterceptor调用的,而DynamicAdvisedInterceptor继承了MethodInterceptor,用于拦截方法调用,并从中获取调用链。

如果是在同一个类中的方法调用,则不会被方法拦截器拦截到,因此事务不会起作用,必须将方法放入另一个类,并且该类通过spring注入。

HttpServletResponse中sendError与setStatus的区别

转载自:https://my.oschina.net/angerbaby/blog/468687

*近在开发项目时,由于前端代码调用后端接口,需要使用响应状体码告知前端登录异常(401)和权限验证不通过(403)。前端拿到对应的状态码会做出相应的处理。

上述的登录验证和权限验证,后端采用Spring拦截器技术实现。为了返回指定的状态码,使用了HttpServletResponse中的setStatus方法。一切都正常运行,没问题!但突然我有了个想法,如果登录验证不通过,需要跳转到专门负责显示401友好提示信息的页面,如何做?有人会说使用sendRedirect方法,可以。还有吗?

我的做法是直接根据响应状态码,依赖web.xml中的error-page配置实现报错页面的跳转。相信下面代码的配置,搞JavaWeb开发的人应该都会熟悉:

  1. <error-page>
  2. <error-code>401</error-code>
  3. <location>/WEB-INF/view/401.jsp</location>
  4. </error-page>

但在真正运行时发现,setStatus确实可以设置response的状态码,却无法像设想的那样,显示出401.jsp页面中的内容。经过一番搜索查证,发现使用sendError代替setStatus,可以达到期望的效果。可是,为什么?sendError和setStatus有何区别?下面是直译官方API文档的内容:

sendError(int sc):使用指定的状态码并清空缓冲,发送一个错误响应至客户端。如果响应已经被提交,这个方法会抛出IllegalStateException。使用这个方法后,响应则应该被认为已被提交,且不应该再被进行写操作了。

sendError(int sc, String msg):使用指定的状态码发送一个错误响应至客户端。服务器默认会创建一个HTML格式的服务错误页面作为响应结果,其中包含参数msg指定的文本信息,这个HTML页面的内容类型为“text/html”,保留cookies和其他未修改的响应头信息。如果一个对应于传入的错误码的错误页面已经在web.xml中声明,那么这个声明的错误页面将会优先于建议的msg参数服务于客户端。(ps:相比较上面的方法,我更倾向于前者。使用上面的方法,可以通过定制不同状态的响应结果显示于客户端,我们应该不想让客户端看到服务器创建出的简单粗暴的页面吧?)

setStatus(int sc):设置响应的状态码。这个方法被用于当响应结果正常时(例如,状态码为SC_OK或SC_MOVED_TEMPORARTLY)设置响应状态码。如果发生错误,而且来访者希望调用在web应用中定义的错误页面作为显示,那么应该使用sendError方法代替之。使用setStatus方法之后,容器会清空缓冲并设置Location响应头,保留cookies和其他响应头信息。

从直译的结果不难发现哈,sendError适用于报错且存在对应的报错页面配置作为输出显示的情况,而setStatus适用于正常响应的情况,仅仅可以改变响应状态码而已。

spring中bean之间的引用以及内部bean

转载自:https://www.cnblogs.com/sxdcgaq8080/p/5680612.html

在spring中会有如下的几种情况:

1.在当前容器中,(即在spring.xml这一个配置文件中),一个bean引用了另一个bean。

使用

1》  <ref  bean=”另一个bean的id” />

1.1 构造器

%title插图%num

1.2 setter

%title插图%num

 

  2》ref作属性

—–2.1  -构造器注入:<constructor-arg   index=”0″  ref=”另一个bean的id”  />

%title插图%num

 

—–2.2-setter注入:<property   name=” ”  ref=”另一个bean的id”  />

 

%title插图%num

 

2.<ref  local=” “>

引用当前容器中的另一个<bean>,只能通过引用这样定义的<bean>即:<bean  id=”bean1″  class=””/> 定义id的可以被识别.

其余的<bean  name=”bean2″  class=””> 或者<bean alias=”bean3″  class=””>都识别不到。

%title插图%num

 

3.<ref parent=””  />

引用父容器中的bean,若父容器中定义的<bean  id=”bean1″ class=”” />,当前容器中也有一个<bean  id=”bean1″ class=””/> 则<ref parent =””>会直接去父容器中去找,如果没有那就是没有,不会在当前容器中寻找。

%title插图%num

 

4.内部bean

1.在<property>或<constructor-arg>内部通过<bean>定义的,

2.该bean不管是否指定id或者name,该bean都有一个唯一的匿名标识符,且不能被指定别名

3.该bean队其他外部的bean不可见。

%title插图%num

Synchronized锁在Spring事务管理下,为啥还线程不安全

开启10000个线程,每个线程给员工表的money字段【初始值是0】加1,没有使用悲观锁和乐观锁,但是在业务层方法上加了synchronized关键字,问题是代码执行完毕后数据库中的money 字段不是10000,而是小于10000 问题出在哪里?

Service层代码:

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

SQL代码(没有加悲观/乐观锁):

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

用1000个线程跑代码:

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

简单来说:多线程跑一个使用synchronized关键字修饰的方法,方法内操作的是数据库,按正常逻辑应该*终的值是1000,但经过多次测试,结果是低于1000。这是为什么呢?

一、我的思考

既然测试出来的结果是低于1000,那说明这段代码不是线程安全的。不是线程安全的,那问题出现在哪呢?众所周知,synchronized方法能够保证所修饰的代码块、方法保证有序性、原子性、可见性。

讲道理,以上的代码跑起来,问题中Service层的increaseMoney()是有序的、原子的、可见的,所以断定跟synchronized应该没关系。

(参考我之前写过的synchronize锁笔记:Java锁机制了解一下)

既然Java层面上找不到原因,那分析一下数据库层面的吧(因为方法内操作的是数据库)。在increaseMoney()方法前加了@Transcational注解,说明这个方法是带有事务的。事务能保证同组的SQL要么同时成功,要么同时失败。讲道理,如果没有报错的话,应该每个线程都对money值进行+1。从理论上来说,结果应该是1000的才对。

(参考我之前写过的Spring事务:一文带你看懂Spring事务!)

根据上面的分析,我怀疑是提问者没测试好(hhhh,逃),于是我也跑去测试了一下,发现是以提问者的方式来使用是真的有问题

首先贴一下我的测试代码:

@RestController
public class EmployeeController {
 @Autowired
 private EmployeeService employeeService;
 @RequestMapping("/add")
 public void addEmployee() {
 for (int i = 0; i < 1000; i++) {
 new Thread(() -> employeeService.addEmployee()).start();
 }
 }
}
@Service
public class EmployeeService {
 @Autowired
 private EmployeeRepository employeeRepository;
 @Transactional
 public synchronized void addEmployee() {
 // 查出ID为8的记录,然后每次将年龄增加一
 Employee employee = employeeRepository.getOne(8);
 System.out.println(employee);
 Integer age = employee.getAge();
 employee.setAge(age + 1);
 employeeRepository.save(employee);
 }
}

简单地打印了每次拿到的employee值,并且拿到了SQL执行的顺序,如下(贴出小部分):

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

从打印的情况我们可以得出:多线程情况下并没有串行执行addEmployee()方法。这就导致对同一个值做重复的修改,所以*终的数值比1000要少。

二、图解出现的原因

发现并不是同步执行的,于是我就怀疑synchronized关键字和Spring肯定有点冲突。于是根据这两个关键字搜了一下,找到了问题所在。

我们知道Spring事务的底层是Spring AOP,而Spring AOP的底层是动态代理技术。跟大家一起回顾一下动态代理:

 public static void main(String[] args) {
 // 目标对象
 Object target ;
 Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), Main.class, new InvocationHandler() {
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 // 但凡带有@Transcational注解的方法都会被拦截
 // 1... 开启事务
 method.invoke(target);
 // 2... 提交事务
 return null;
 }
 
 });
 }

(详细请参考我之前写过的动态代理:给女朋友讲解什么是代理模式)

实际上Spring做的处理跟以上的思路是一样的,我们可以看一下TransactionAspectSupport类中invokeWithinTransaction():

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

调用方法开启事务,调用方法提交事务

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

在多线程环境下,就可能会出现:方法执行完了(synchronized代码块执行完了),事务还没提交,别的线程可以进入被synchronized修饰的方法,再读取的时候,读到的是还没提交事务的数据,这个数据不是*新的,所以就出现了这个问题。

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

三、解决问题

从上面我们可以发现,问题所在是因为@Transcational注解和synchronized一起使用了,加锁的范围没有包括到整个事务。所以我们可以这样做:

新建一个名叫SynchronizedService类,让其去调用addEmployee()方法,整个代码如下:

@RestController
public class EmployeeController {
 @Autowired
 private SynchronizedService synchronizedService ;
 @RequestMapping("/add")
 public void addEmployee() {
 for (int i = 0; i < 1000; i++) {
 new Thread(() -> synchronizedService.synchronizedAddEmployee()).start();
 }
 }
}
// 新建的Service类
@Service
public class SynchronizedService {
 @Autowired
 private EmployeeService employeeService ;
	
 // 同步
 public synchronized void synchronizedAddEmployee() {
 employeeService.addEmployee();
 }
}
@Service
public class EmployeeService {
 @Autowired
 private EmployeeRepository employeeRepository;
 
 @Transactional
 public void addEmployee() {
 // 查出ID为8的记录,然后每次将年龄增加一
 Employee employee = employeeRepository.getOne(8);
 System.out.println(Thread.currentThread().getName() + employee);
 Integer age = employee.getAge();
 employee.setAge(age + 1);
 employeeRepository.save(employee);
 }
}

我们将synchronized锁的范围包含到整个Spring事务上,这就不会出现线程安全的问题了。在测试的时候,我们可以发现1000个线程跑起来比之前要慢得多,当然我们的数据是正确的:

搞不懂,Synchronized锁在Spring事务管理下,为啥还线程不安全?

 

*后

可以发现的是,虽然说Spring事务用起来我们是非常方便的,但如果不了解一些Spring事务的细节,很多时候出现Bug了就百思不得其解。还是得继续加油努力呀~~~

 

Spring简介-入门级学习

Spring简介:

       Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
       Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
       轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
       控制反转:Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
       面向切面:Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
       容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
       框架:Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
       所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
Spring模块:
       Spring框架由七个定义明确的模块组成,如下图:
       %title插图%num 

如果作为一个整体,这些模块为你提供了开发企业应用所需的一切。但你不必将应用完全基于Spring框架。你可以自由地挑选适合你的应用的模块而忽略其余的模块。

 

Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用,如下图:

%title插图%num

 

核心容器:

所有的Spring模块都是在核心容器之上构建的,是Spring框架*基础的部分,它提供了依赖注入(DependencyInjection)特征来实现容器对Bean的管理

核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

*)spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能

*)spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦

*)context模块建立在由core和 beans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象

Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能

Context模块也支持Java EE的功能,比如EJB、JMX和远程调用等

            ApplicationContext接口是Context模块的焦点

            spring-context-support提供了对第三方库集成到Spring上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等

*)spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等

 

数据访问/集成:

数据访问/集成层包括 JDBC(Java Data Base Connectivity),ORM(Object Relational Mapping),OXM(Object XML Mapping),JMS(Java Message Service) 和事务处理模块,它们的细节如下:

       *JDBC 模块提供了JDBC抽象层,它消除了冗长的JDBC编码和对数据库供应商特定错误代码的解析

       *ORM 模块提供了对流行的对象关系映射API的集成,包括JPA、JDO和Hibernate等。通过此模块可以让这些ORM框架和spring的其它功能整合,比如前面提及的事务管理

       *OXM 模块提供了对OXM实现的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等

       *JMS 模块包含生产(produce)和消费(consume)消息的功能。从Spring 4.1开始,集成了spring-messaging模块

*)事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写beginTransaction()、commit()、rollback()等事务管理方法,声明式事务是通过注解或配置由spring自动处理,编程式事务粒度更细)

 

Web:

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

       *Web 模块提供面向web的基本功能和面向web的应用上下文,比如多部分(multipart)文件上传功能、使用Servlet监听器初始化IoC容器等。它还包括HTTP客户端以及Spring远程调用中与web相关的部分

       *Web-MVC 模块为web应用提供了模型视图控制(MVC)和REST Web服务的实现。Spring的MVC框架可以使领域模型代码和web表单完全地分离,且可以与Spring框架的其它所有功能进行集成

       *Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式

*)Web-Portlet 模块提供了用于Portlet环境的MVC实现,并反映了spring-webmvc模块的功能

 

       其他

       还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

       *AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中

       *Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架

       *Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现

       *Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息

*)测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试

 

环境配置:

1、安装JDK(可参考我的另一篇博文:安装 Java 开发工具包JDK(Windows版本))

2、安装Eclipse IDE

3、安装Spring 框架库

a)在http://repo.spring.io/release/org/springframework/spring/下载*新版本的Spring 框架的二进制文件(我是Windows系统下载了spring-framework-5.1.0.RELEASE-dist.zip)

b)将下载下来的文件解压

\libs文件夹中会显示所有的Spring 库

%title插图%num

 

创建一个Hello World实例:

1、使用 Eclipse IDE 创建一个简单的 Java 项目

2、添加 Spring 框架

选中项目 -> 右键属性 -> Java Build Path,开始添加,如下图红框部分:

%title插图%num

其中,在添加jar包时,只需要添加核心jar包就可以,如下图红框部分:

%title插图%num

 

3、按下图红框部分,创建3个源文件:HelloWorld.java 、 MainApp.java、Beans.xml

%title插图%num

其中:

HelloWorld.java的代码:

 1 package com.tutorialspoint;
 2 
 3 public class HelloWorld {
 4    private String message;
 5    public void setMessage(String message){
 6       this.message  = message;
 7    }
 8    public void getMessage(){
 9       System.out.println("Your Message : " + message);
10    }
11 }

 

MainApp.java的代码:

(备注:

1、使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文。这个 API 加载 beans 的配置文件并*终基于所提供的 API,它处理创建并初始化所有的对象,即在配置文件中提到的 beans;

2、使用已创建的上下文的 getBean() 方法来获得所需的 bean。这个方法使用 bean 的 ID 返回一个*终可以转换为实际对象的通用对象。一旦有了对象,你就可以使用这个对象调用任何类的方法。)

 1 package com.tutorialspoint;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class MainApp {
 7    public static void main(String[] args) {
 8       ApplicationContext context = 
 9              new ClassPathXmlApplicationContext("Beans.xml");
10       HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
11       obj.getMessage();
12    }
13 }

 

Beans.xml的代码:

(备注:该文件用于给不同的 bean 分配唯一的 ID,并且控制不同值的对象的创建,而不会影响 Spring 的任何源文件)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <beans xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 7 
 8    <bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
 9        <property name="message" value="Hello World!"/>
10    </bean>
11 
12 </beans>

 

4、运行程序

%title插图%num

截止到现在,已经成功地创建了*个 Spring 应用程序,后续就需要更加深入的去了解Spring了。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速