(spring-第4回【IoC基础篇】)spring基于注解的配置

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

基于xml的bean属性配置:bean的定义信息与bean的实现类是分离的。

基于注解的配置:bean的定义信息是通过在bean实现类上标注注解实现。

也就是说,加了注解,相当于在XML中配置了,一样一样的。

一、举个栗子:

1packagecom.mesopotamia.annotation;23importorg.sPRingframework.stereotype.Component;45@Component6publicclassCar {7privateString name;8privateString color;9privatedoubleprice;10publicCar(){11name="保时捷";12color="黄色";13}14publicString getName() {15returnname;16}17publicvoidsetName(String name) {18this.name =name;19}20publicString getColor() {21returncolor;22}23publicvoidsetColor(String color) {24this.color =color;25}26publicdoublegetPrice() {27returnprice;28}29publicvoidsetPrice(doubleprice) {30this.price =price;31}3233publicString toString(){34return"名字:"+name+" 颜色:"+color+" 价格:"+price;35}36}

第5行标注Component:spring看到这个属性标志,会自动将Car变成容器管理类,等同于在XML中这样配置:

1<bean id="car"class="com.mesopotamia.annotation.Car"></bean>

二、spring启动之前的配置?

1<?xml version="1.0" encoding="UTF-8"?>2<beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xmlns:context="http://www.springframework.org/schema/context"5xsi:schemaLocation="http://www.springframework.org/schema/beans6http://www.springframework.org/schema/beans/spring-beans-3.0.xsd7http://www.springframework.org/schema/context8http://www.springframework.org/schema/context/spring-context-3.0.xsd"9>10<context:component-scanbase-package="com.mesopotamia.annotation"/>11</beans>

如上,

使用空间:context,

使用context的规则:component-scan.

第10行的意义:扫描这个包中的所有类,并从注解信息中获取bean的基本信息(没加注解的不扫描也不实例化)。

三、如何启动?

按正常方式启动即可加载(自己复习spring容器的加载),例如:

1packagecom.mesopotamia.annotation;23importorg.springframework.context.applicationContext;4importorg.springframework.context.support.ClassPathXmlApplicationContext;56publicclassMain {78publicstaticvoidmain(String args[]){9ApplicationContext ctx =newClassPathXmlApplicationContext("com/mesopotamia/annotation/beans.xml");10Car car= ctx.getBean(Car.class);11System.out.println(car.toString());12}1314}

第10行就已经实例化Car了,并且实例化之前先跑了Car的构造函数给car的属性附了值(因为我给构造函数里专门写了赋值语句,没写的话,属性是没有赋值的,除非见了鬼)。

下面是打印信息,从下面第4行结果可以看到已经附了值。

12015-11-13 23:44:18,414 INFO [main] (AbstractApplicationContext.java:456) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@e80a59: startup date [Fri Nov 13 23:44:18 CST 2015]; root of context hierarchy22015-11-13 23:44:18,480 INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions fromclasspath resource [com/mesopotamia/annotation/beans.xml]32015-11-13 23:44:18,728 INFO [main] (DefaultListableBeanFactory.java:555) - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@121ab80: defining beans [car,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor]; root of factory hierarchy4名字:保时捷 颜色:黄色 价格:0.0

四、context:component-scan的配置直接选了相应包里的全部class,有没有更多的过滤方式?

有。context:component-scan标签下面可以再加子标签,如:

1<context:component-scanbase-package="com.baobaotao">2<context:include-filtertype="aspectj"expression="com.baobaotao.anno.*Plugin+"/>3<context:exclude-filtertype="regex"expression="cn\.outofmemory\.spring\.[^.]+(Dao|Service)"/>

4</context:component-scan>

include-filter表示:包含哪些。type是类型,expression是表达式过滤。

exclude-filter表示:除去哪些。type是类型,expression是表达式过滤。

第二行表示:com.baobaotao.anno包下面所有以Plugin结尾的class。

第三行表示:除去所有以Dao或者Service结束的类。具体规则这里先不作讨论,你要觉得你行,那你自己先啃啃里面的肉(先去复习一下正则表达式)

其他过滤表达式举例:

五、除了Component外,其他的注解都有什么?

1、@Component 一般的bean类上面配置。2、@Controller 对应表现层的Bean,也就是action。3、@ Service 对应业务层bean。4、@ Repository 对应持久层Bean。上面的4种起到相同的效果,都是注入bean,注入bean的四大金刚,张龙赵虎王朝马汉,辅佐包黑炭。

5、@Autowired 成员变量或方法入参处标注,按类型匹配自动注入。

6、@Qualifier 按名称匹配方式注入。

7、@PostConstruct指定初始化方法。(相当于XML配置中的init-method)

8、@PreDestroy指定销毁方法。(相当于XML配置中的destroy-method)

9、@Scope 指定bean是prototype还是singleton。

六、上面这几个注解给个具体例子说明下?

不想往下看的可以去陪女朋友了,因为重点已经讲完了。下面是一个简单登录界面的栗子,为了突出重点,关于spring web方面的机制暂时不讲,只讲有关注解的部分,如果你还没看过spring web应用部分也无妨,下面的例子只涉及注解注入部分:

XML配置文件如下:

1<?xml version="1.0" encoding="UTF-8"?>2<beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xmlns:p="http://www.springframework.org/schema/p"5xmlns:context="http://www.springframework.org/schema/context"6xmlns:aop="http://www.springframework.org/schema/aop"7xmlns:tx="http://www.springframework.org/schema/tx"8xsi:schemaLocation="http://www.springframework.org/schema/beans9http://www.springframework.org/schema/beans/spring-beans-3.0.xsd10http://www.springframework.org/schema/context11http://www.springframework.org/schema/context/spring-context-3.0.xsd12http://www.springframework.org/schema/tx13http://www.springframework.org/schema/tx/spring-tx-3.0.xsd14http://www.springframework.org/schema/aop15http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">1617<!--扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入-->18<context:component-scanbase-package="com.baobaotao.dao"/>19<context:component-scanbase-package="com.baobaotao.service"/>20<context:component-scanbase-package="com.baobaotao.domain"/>2122<!--配置数据源-->23<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"24destroy-method="close"25p:driverClassName="com.MySQL.jdbc.Driver"26p:url="jdbc:mysql://localhost:3306/sampledb"27p:username="root"28p:passWord="2009118293zjl"/>2930<!--配置Jdbc模板-->31<beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"32p:dataSource-ref="dataSource"/>3334<!--配置事务管理器-->35<beanid="transactionManager"36class="org.springframework.jdbc.datasource.DataSourceTransactionManager"37p:dataSource-ref="dataSource"/>3839<!--通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务-->40<aop:configproxy-target-class="true">41<aop:pointcutid="serviceMethod"42expression=" execution(* com.baobaotao.service..*(..))"/>43<aop:advisorpointcut-ref="serviceMethod"advice-ref="txAdvice"/>44</aop:config>45<tx:adviceid="txAdvice"transaction-manager="transactionManager">46<tx:attributes>47<tx:methodname="*"/>48</tx:attributes>49</tx:advice>50</beans>

重点第18到20行:spring只扫描配置路径下所有带注解的地方来注入相关数据。其他行先不看,你想看我也不拦你。

WEB应用后台java分三层:control、service、dao层,简单讲一下,直接与jsp交互的就是control层,直接操作数据库的是dao层(持久层,数据库里的数据都是持久性的嘛),service层负责把dao层数据拿到,经过处理,返回给control层。control层拿到数据再交给jsp前台。(dao就是程序员,service就是老板,control就是客户,程序员做东西,客户使用,而老板是桥梁)

下面是control层:

1packagecom.baobaotao.web;23importjava.util.Date;45importjavax.annotation.PostConstruct;6importjavax.annotation.PreDestroy;7importjavax.servlet.http.HttpServletRequest;8910importorg.apache.commons.logging.Log;11importorg.apache.commons.logging.LogFactory;12importorg.springframework.beans.factory.annotation.Autowired;13importorg.springframework.stereotype.Controller;14importorg.springframework.web.bind.annotation.RequestMapping;15importorg.springframework.web.servlet.ModelAndView;1617importcom.baobaotao.domain.User;18importcom.baobaotao.service.UserService;1920@Controller21publicclassLoginController{22Log log=LogFactory.getLog(LoginController.class);2324@Autowired(required=false)25privateUserService userService;2627@RequestMapping(value = "/loginCheck.do")28publicModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){29booleanisValidUser =userService.hasMatchUser(loginCommand.getUserName(),loginCommand.getPassword());30if(!isValidUser) {31returnnewModelAndView("login", "error", "用户名或密码错误。");32}else{33User user =userService.findUserByUserName(loginCommand34.getUserName());35user.setLastip(request.getLocalAddr());36user.setLastVisit(newDate());37userService.loginSuccess(user);38request.getsession().setAttribute("user", user);3940returnnewModelAndView("main");41}42}4344@PostConstruct45publicvoidinit(){46log.info("本应用程序正式拉开帷幕。。。");47}4849@PreDestroy50publicvoiddestroy(){51log.info("本应用程序正式落幕,吓吓侬。。。");52}53}

这里用到了几个注解,

spring看到@Controller会如同看到@Component一样,转换成spring容器管理的bean。

spring看到@Autowired(required=false)会自动注入(实例化)下面的userService。(直接用就行,就不用你来new一个对象啦)。

spring看到@PostConstruct就会在实例化本Bean后接着执行这个方法;

spring看到@PreDestroy就会在销毁之前执行下面的方法;

你的眼神告诉我你不相信我。好的,咱们看日志:

tomcat启动的时候spring容器会自动加载,下面是tomcat启动的日志:

1。。。。。。232015-11-15 21:24:31,673 DEBUG [main] (DefaultSingletonBeanRegistry.java:214) - Creating shared instance of singleton bean 'userDao'42015-11-15 21:24:31,674 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:430) - Creating instance of bean 'userDao'52015-11-15 21:24:31,674 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'67。。。。。。892015-11-15 21:24:31,676 DEBUG [main] (InjectionMetadata.java:82) - Processing injected method of bean 'userDao': AutowiredFieldElementforprivateorg.springframework.jdbc.core.JdbcTemplate com.baobaotao.dao.UserDao.jdbcTemplate102015-11-15 21:24:31,677 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'jdbcTemplate'112015-11-15 21:24:31,677 DEBUG [main] (AutowiredAnnotationBeanPostProcessor.java:420) - Autowiring by type from bean name 'userDao' to bean named 'jdbcTemplate'1213。。。。。。14152015-11-15 21:24:31,678 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'userDao'161718。。。。。。19202015-11-15 21:24:31,679 DEBUG [main] (DefaultSingletonBeanRegistry.java:214) - Creating shared instance of singleton bean 'userService'212015-11-15 21:24:31,679 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:430) - Creating instance of bean 'userService'222015-11-15 21:24:31,679 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'232015-11-15 21:24:31,680 INFO [main] (UserService.java:18) -实例化了UserService...2425。。。。。。26272015-11-15 21:24:31,683 DEBUG [main] (InjectionMetadata.java:82) - Processing injected method of bean 'userService': AutowiredFieldElementforprivatecom.baobaotao.dao.UserDao com.baobaotao.service.UserService.userDao282015-11-15 21:24:31,685 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'userDao'292015-11-15 21:24:31,685 DEBUG [main] (AutowiredAnnotationBeanPostProcessor.java:420) - Autowiring by type from bean name 'userService' to bean named 'userDao'302015-11-15 21:24:31,686 DEBUG [main] (InjectionMetadata.java:82) - Processing injected method of bean 'userService': AutowiredFieldElementforprivatecom.baobaotao.dao.LoginLogDao com.baobaotao.service.UserService.loginLogDao312015-11-15 21:24:31,686 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'loginLogDao'322015-11-15 21:24:31,687 DEBUG [main] (AutowiredAnnotationBeanPostProcessor.java:420) - Autowiring by type from bean name 'userService' to bean named 'loginLogDao'3334。。。。。。35362015-11-15 21:24:32,093 INFO [main] (UserService.java:18) -实例化了UserService...372015-11-15 21:24:32,094 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'userService'382015-11-15 21:24:32,094 DEBUG [main] (DefaultSingletonBeanRegistry.java:214) - Creating shared instance of singleton bean 'loginLog'3940。。。。。。4142015-11-15 21:24:32,252 INFO [main] (DefaultListableBeanFactory.java:555) - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c272bc: defining beans [loginController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@691dee432015-11-15 21:24:32,252 DEBUG [main] (DefaultSingletonBeanRegistry.java:214) - Creating shared instance of singleton bean 'loginController'442015-11-15 21:24:32,254 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:430) - Creating instance of bean 'loginController'452015-11-15 21:24:32,255 INFO [main] (LoginController.java:25) -实例化了LoginController...462015-11-15 21:24:32,264 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:200) - Found init method onclass[com.baobaotao.web.LoginController]:publicvoidcom.baobaotao.web.LoginController.init()472015-11-15 21:24:32,265 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:208) - Found destroy method onclass[com.baobaotao.web.LoginController]:publicvoidcom.baobaotao.web.LoginController.destroy()482015-11-15 21:24:32,265 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:251) - Found init method onclass[com.baobaotao.web.LoginController]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement@316510492015-11-15 21:24:32,265 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:259) - Found destroy method onclass[com.baobaotao.web.LoginController]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement@5cd39ffa502015-11-15 21:24:32,266 DEBUG [main] (InjectionMetadata.java:59) - Found injected element onclass[com.baobaotao.web.LoginController]: AutowiredFieldElementforprivatecom.baobaotao.service.UserService com.baobaotao.web.LoginController.userService512015-11-15 21:24:32,267 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:504) - Eagerly caching bean 'loginController' to allowforresolving potential circular references522015-11-15 21:24:32,268 DEBUG [main] (InjectionMetadata.java:82) - Processing injected method of bean 'loginController': AutowiredFieldElementforprivatecom.baobaotao.service.UserService com.baobaotao.web.LoginController.userService532015-11-15 21:24:32,269 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'userService'542015-11-15 21:24:32,270 DEBUG [main] (AutowiredAnnotationBeanPostProcessor.java:420) - Autowiring by type from bean name 'loginController' to bean named 'userService'552015-11-15 21:24:32,271 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:291) - Invoking init method on bean 'loginController':publicvoidcom.baobaotao.web.LoginController.init()562015-11-15 21:24:32,271 INFO [main] (LoginController.java:50) -本应用程序正式拉开帷幕。。。572015-11-15 21:24:32,271 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'loginController'5859。。。。。。

第44、45行是实例化LoginController,

第46/47行是根据@PostContruct和@PreDestroy发现了我们定义的初始化和销毁方法。

第53行,spring直接给了我们一个userService对象(因为它看到了@Autowired,required=false是说如果找不到对应的bean不报异常)。

第56行,spring看到@PostContruct执行了初始化方法。

当我把tomcat停掉,spring容器就会销毁,那么是不是要执行@PreDestroy下面的销毁方法?当然,你要相信科学,看停掉tomcat的日志:

。。。。。52015-11-15 21:53:15,763 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:303) - Invoking destroy method on bean 'loginController':publicvoidcom.baobaotao.web.LoginController.destroy()62015-11-15 21:53:15,763 INFO [main] (LoginController.java:55) -本应用程序正式落幕,吓吓侬。。。72015-11-15 21:53:15org.apache.catalina.core.ApplicationContext log8信息: Closing Spring root WebApplicationContext92015-11-15 21:53:15,764 INFO [main] (AbstractApplicationContext.java:1002) - Closing Root WebApplicationContext: startup date [Sun Nov 15 21:24:29 CST 2015]; root of context hierarchy

第六行果然执行了销毁方法。

请解释前面那个日志里第53行的Returning cached instance of singleton bean 'userService'。

是这样的,先看UserService的部分代码:

1@Service2publicclassUserService {3privatestaticLog log=LogFactory.getLog(UserService.class);4publicUserService(){5log.info("实例化了UserService...");6}

我在这个类中注释了@Service,spring在启动的时候跟@Component、@Controller、@Repository一样,会自动把bean信息注入容器中(即把bean在spring容器中实例化),也就是说,当spring看到@Service时,会自动返回一个提前实例化好的UserService,而只要UserService上面不显式标注:@Scope("prototype"),那么默认UserService就是单例模式的。单例模式下,spring会把bean放到IoC容器的缓存池中,而把bean的引用返回给调用者。这就是Returning cached instance of singleton bean 'userService'这句话的意义。

好的,我把UserService的注解改成下面的方式:

1@Service2@Scope("prototype")3publicclassUserService {4privatestaticLog log=LogFactory.getLog(UserService.class);5publicUserService(){6log.info("实例化了UserService...");7}8

那么启动tomcat打印日志如下:

12015-11-15 22:11:09,723 DEBUG [main] (Cglib2AopProxy.java:755) - Method is declared on Advisedinterface:publicabstractintorg.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)22015-11-15 22:11:09,724 DEBUG [main] (Cglib2AopProxy.java:755) - Method is declared on Advisedinterface:publicabstractintorg.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)32015-11-15 22:11:09,724 DEBUG [main] (Cglib2AopProxy.java:755) - Method is declared on Advisedinterface:publicabstractjava.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()42015-11-15 22:11:09,760 INFO [main] (UserService.java:20) -实例化了UserService...52015-11-15 22:11:09,760 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'userService'62015-11-15 22:11:09,761 DEBUG [main] (AutowiredAnnotationBeanPostProcessor.java:420) - Autowiring by type from bean name 'loginController' to bean named 'userService'72015-11-15 22:11:09,761 DEBUG [main] (InitDestroyAnnotationBeanPostProcessor.java:291) - Invoking init method on bean 'loginController':publicvoidcom.baobaotao.web.LoginController.init()82015-11-15 22:11:09,761 INFO [main] (LoginController.java:50) -本应用程序正式拉开帷幕。。。92015-11-15 22:11:09,761 DEBUG [main] (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'loginController'102015-11-15 22:11:09,761 DEBUG [main] (AbstractBeanFactory.java:242) - Returning cached instance of singleton bean 'org.springframework.context.annotati

你会看到,在拉开帷幕之前,又实例化了一次UserService,这就是prototype的作用。

再看:

1@Controller2publicclassLoginController{3Log log=LogFactory.getLog(LoginController.class);45publicLoginController(){6log.info("实例化了LoginController...");7}89@Autowired(required=false)10@Qualifier("service")11privateUserService userService;12

第10行,我在userService上面加了 @Qualifier("service")的注释,这个表示,我引用的是名字为service的bean的实例,那么你要给UserService起个名字叫service:

1@Service("service")2@Scope("prototype")3publicclassUserService {4privatestaticLog log=LogFactory.getLog(UserService.class);5publicUserService(){6log.info("实例化了UserService...");7}8

像第一行那样。(Component、Controller、Repository也是那样命名,如果是基于XML的注入如何命名?自己复习去。)

不加的话,系统找不到对应的bean,就会报错。

spring容器的三座大山:XML配置文件(或者注解配置、bean配置等),spring容器,bean类。不管是基于XML还是基于注解,无非就是为了把bean信息注入到spring容器中,南拳和北腿,各有千秋。下面是二者的对比:

本节内容就讲到这里。

吾生也有涯,而知也无涯。

——《庄子》

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航