相关文章:Spring学习笔记-AOP
慢慢接触spring框架,将所学所用的东西记录下来,点点滴滴,肯定会有所收获。
之所以使用Spring框架,是因为框架可以大量简化程序的开发工作,更加高效稳定的开发大型程序。
IoC(Inversion of Control)控制反转,就是在一般情况下,获取类的实例必须要在程序中new这个类,现在不需要这样了,直接通过配置xml文件,或者对类进行注解,在一个叫做IOC容器的东西里,就存在了类的实例,我们称之为bean,通过在IOC即可获取到要得到的实例。
在Eclipse上使用Spring框架,首先要安装spring在Eclipse上的插件springsource-tool-suite-3.7.1.RELEASE,为了Eclipse上使用spring。
下载下来后,在安装软件里安装好。
下载spring的jar包spring-framework-4.2.2.RELEASE-dist.zip,里边lib里有使用spring时的jar包。
下载commons-logging包,spring的日志系统所依赖。
将这些5个jar包配置在项目中:
创建一个HelloWorld类:
package com.cqupt.spring.beans; public class Helloworld { private String name; public void setName(String name){ this.name=name; } public void hello(){ System.out.println("hello :"+name); } }***配置xml文件,在src下新建spring Bean Configration File 文件,在beans标签下新建bean标签
<bean id="helloworld" class="com.cqupt.spring.beans.Helloworld"> <property name="name" value="CQUPT"></property> </bean>
注意,使用property配置属性,类中必须要有无参构造函数,因为原理是先使用无参构造函数构造类对象,然后使用set方法配置属性
id代表这个bean的唯一标示,class是映射到的类,property是类里的成员属性配置,name的识别是根据setter函数识别的,如setName2(String ),那么name="name2",value就是给成员属性配置的值。
在main函数中使用spring
public static void main(String[] args){ //1、创建spring的IOC容器 ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml"); //2、从IOC容器中获取Bean实例 Helloworld helloworld = (Helloworld) ac.getBean("helloworld"); helloworld.hello(); }注:在执行
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");这条语句时,其实已将创建了Helloworld的实例,也调用了Set方法。
getBean有两种方式:根据xml中的id,一种是根据Helloworld.class,区别就是两个bean标签映射到同一类时,getBean(类.class)会出错。
Spring提供两种类型的IOC容器,BeanFactory和ApplicationContext,其中ApplicationContext是对于使用Spring的开发人员的,BeanFactory是Spring的底层,不经常使用。
ApplicationContext是一个接口,有两种IOC的实现类,ClassPathXmlApplicationContext(依据类路径)和FileSystemXmlApplicationContext(依据系统文件路径);
三种注入方式:属性注入,构造器注入,工厂方法注入(不推荐,很少用)
属性注入:依据Set方法,最常用的方式;
构造方法注入:constructor-arg标签
创建一个Car类,构造函数
package com.cqupt.spring.beans; public class Car { private String brand; private String corp; private int price; private int maxSpeed; public Car(String brand, String corp, int price) { super(); this.brand = brand; this.corp = corp; this.price = price; } @Override public String toString() { return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price + ", maxSpeed=" + maxSpeed + "]"; } }xml配置
<bean id="car" class="com.cqupt.spring.beans.Car"> <constructor-arg value="Audi" index="0"></constructor-arg> <constructor-arg value="Shanghai" index="1"></constructor-arg> <constructor-arg value="30000" index="2"></constructor-arg> </bean>index可以不需要,但是写出来时,一定要注意与第几个value值的匹配,否则出错
main函数中使用:
public static void main(String[] args){ //1、创建spring的IOC容器 ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml"); Car car = (Car) ac.getBean("car"); System.out.println(car); }注:当出现重载构造函数时,可用type属性进行区分,一个构造函数对应一个bean标签,一个参数对应一个constructor-arg标签
<bean id="car" class="com.cqupt.spring.beans.Car"> <constructor-arg value="Audi" index="0"></constructor-arg> <constructor-arg value="Shanghai" index="1"></constructor-arg> <constructor-arg value="30000" index="2" type="double"></constructor-arg> </bean> <bean id="car2" class="com.cqupt.spring.beans.Car"> <constructor-arg value="Boma" index="0" type="java.lang.String"></constructor-arg> <constructor-arg value="Beijing" index="1" type="java.lang.String"></constructor-arg> <constructor-arg value="500" index="2" type="int"></constructor-arg> </bean>
<constructor-arg index="1" type="java.lang.String"> <value><![CDATA[<shanghai>]]></value> </constructor-arg>
<bean id="person" class="com.cqupt.spring.beans.Person"> <property name="name" value="lihua"></property> <property name="age" value="23"></property> <!-- 第一种 <property name="car" > <ref bean="car"></ref> </property> --> <property name="car" ref="car2"></property> </bean>
<bean id="person" class="com.cqupt.spring.beans.Person"> <property name="name" value="lihua"></property> <property name="age" value="23"></property> <property name="car"> <!-- 内部bean --> <bean id="car3" class="com.cqupt.spring.beans.Car"> <constructor-arg value="Ford"></constructor-arg> <constructor-arg value="changan"></constructor-arg> <constructor-arg value="200" type="int"></constructor-arg> </bean> </property> </bean>
<constructor-arg name="maxSpeed" value="200" ></constructor-arg>
<property name="car"><null></null></property>
<bean id="person" class="com.cqupt.spring.beans.Person"> <property name="name" value="lihua"></property> <property name="age" value="23"></property> <property name="car"> <!-- 内部bean --> <bean id="car3" class="com.cqupt.spring.beans.Car"> <property name="brand" value="Ford"></property> <property name="corp" value="changan"></property> <property name="maxSpeed" value="200"></property> </bean> </property> <!-- 级联属性赋值 --> <property name="car.price" value="10000"></property> </bean>
<property name="car"><null></null></property> <!-- 级联属性赋值 --> <property name="car.price" value="10000"></property>出错
在property标签下,使用list、set、map标签
Person类有集合属性cars
public List<Car> getCars(){ return cars; } public void setCars(List<Car> cars){ this.cars=cars; } private String name; private int age; private List<Car> cars;xml配置
<property name="cars"> <list> <ref bean="car"></ref> <ref bean="car2"></ref> </list> </property>
也可以配置内部bean
<property name="cars"> <list> <ref bean="car"></ref> <ref bean="car2"></ref> <bean class="com.cqupt.spring.beans.Car"> <constructor-arg value="Ford" ></constructor-arg> <constructor-arg value="changan" ></constructor-arg> <constructor-arg value="250" type="int"></constructor-arg> </bean> </list> </property>
使用<map><entry key="" value-ref="beanid">标签
Person类
public Map<String , Car> getCars(){ return cars; } public void setCars(Map<String,Car> cars){ this.cars=cars; } private String name; private int age; private Map<String, Car> cars;Xml
<property name="cars"> <map> <entry key="AA" value-ref="car"></entry> <entry key="BB" value-ref="car2"></entry> </map> </property>
在property标签下,使用<props><prop></prop></props>标签
DataSource类,含有Properties属性
public class DataSource { public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } private Properties properties; }
<bean id="dataSource" class="com.cqupt.spring.beans.DataSource"> <property name="properties"> <props> <prop key="user">lihua</prop> <prop key="password">123456</prop> <prop key="Url">www.baidu.com</prop> </props> </property> </bean>
单独配置一个bean集合,供不同的property使用,需在xml中引入util命名空间<util:list><ref bean=""/></util:list>
<util:list id="cars"> <ref bean="car"></ref> <ref bean="car2"></ref> </util:list>
<bean id="person" class="com.cqupt.spring.beans.Person"> <property name="name" value="lihua"></property> <property name="age" value="23"></property> <property name="cars" ref="cars"></property> </bean>
先导入命名空间p,可以简化配置bean属性,bean引用注意,使用cars-ref=“beanid”
<bean id="person2" class="com.cqupt.spring.beans.Person" p:name="jack" p:age="18" p:cars-ref="cars"></bean>
自动装配,是通过在bean标签里设置autowire属性,让系统根据名称还是类型进行自动装配。
autowire="byName"是根据引用的bean的名称与类型中的属性名称进行匹配
autowire="byType"是根据引用的bean的类型与类型中的属性类型进行装配,当多个bean指向同类型时,不能根据类型装配,否则异常。、
新建Person类,有Address和Car两个属性,Address和Car均为自定义类型
xml中的配置,先配置address和car的bean,再在person中自动装配这两个bean:
<bean id="address" class="com.cqupt.spring.autowire.Address" p:city="Beijing" p:road="Daxing"></bean> <bean id="car" class="com.cqupt.spring.autowire.Car" p:brand="Boma" p:price="30000"></bean> <!-- <bean id="person" class="com.cqupt.spring.autowire.Person" p:name="jack" p:age="28" p:address-ref="address" p:car-ref="car"></bean> --> <bean id="person" class="com.cqupt.spring.autowire.Person" p:name="bolt" p:age="24" autowire="byName"></bean>
public static void main(String[] args){ ApplicationContext ac=new ClassPathXmlApplicationContext("newApplicationContext.xml"); Person person = (Person)ac.getBean("person"); System.out.println(person); }
注意,autowire装配是有缺点的:1,只要指定autowire,那么所有引用bean都设置成自动装配;2、要么是byName,要么是byType,不够灵活
一般,开发过程中,不使用自动装配。在整合第三方框架时使用。
<bean id="address" class="com.cqupt.spring.autowire.Address" p:city="Beijing" p:road="Daxing"></bean> <bean id="address2" class="com.cqupt.spring.autowire.Address" p:city="Beijing" p:road="FengTai"></bean>
<bean id="address" class="com.cqupt.spring.autowire.Address" p:city="Beijing" p:road="Daxing"></bean> <bean id="address2" p:road="FengTai" parent="address"></bean>父bean可以使实例化bean,也可以是抽象bean,用作模板使用,bean标签设置属性abstract="true",此时父bean 不能实例化,否则出错
<bean id="car2" class="com.cqupt.spring.autowire.Car" p:brand="Audi" ></bean> <bean id="person" class="com.cqupt.spring.autowire.Person" p:name="jack" p:age="26" p:address-ref="address" depends-on="car2">
<bean id="car" class="com.cqupt.spring.autowire.Car" p:brand="Audi" p:price="300000" scope="singleton"></bean>
public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext-scope.xml"); Car car= (Car) ctx.getBean("car"); Car car2= (Car)ctx.getBean("car"); System.out.println(car==car2); }输出结果为true
System.out.println("Car Constructing...");
public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext-scope.xml"); }此时输出结果为:Car Constructing...
public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext-scope.xml"); Car car= (Car) ctx.getBean("car"); Car car2= (Car)ctx.getBean("car"); System.out.println(car==car2); }
user=root password=root driverClass=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql:///testspring配置文件中配置bean,在spring2.5后使用引入命名空间context的方式加载properties文件:<context:property-placeholder location="classpath:name.properties"/>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}"></property> <property name="password" value="${password}"></property> <property name="driverClass" value="${driverClass}"></property> <property name="jdbcUrl" value="${jdbcUrl}"></property> </bean> </beans>程序
public static void main(String[] args) throws SQLException { ApplicationContext ctx= new ClassPathXmlApplicationContext("properties.xml"); DataSource dataSource= (DataSource) ctx.getBean("dataSource"); System.out.println(dataSource.getConnection()); }输出结果为com.mchange.v2.c3p0.impl.NewProxyConnection@17776a8 [wrapping: com.mysql.jdbc.JDBC4Connection@69a10787]
<!-- 使用SpEL 为属性赋字面值 --> <bean id="address" class="com.cqupt.spring.spel.Address" p:city="#{'BeiJing'}" p:road="DaXing" ></bean> <!-- 使用SpEL引用其他类中的静态属性 #{T(java.lang.Math).PI} --> <bean id="car" class="com.cqupt.spring.spel.Car" p:brand="Audi" p:price="500000" p:tyrePerimeter="#{T(java.lang.Math).PI * 80}"></bean> <!-- 1.使用SpEL 引用其他bean 的 属性 2.使用SpEL 做运算,动态配置bean属性 --> <bean id="person" class="com.cqupt.spring.spel.Person" p:name="jack" p:car="#{car}" p:city="#{address.city}" p:info="#{car.price > 300000 ? '金领':'白领'}"> </bean>
public static void main(String[] args){ ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-spel.xml"); Address address = (Address) ctx.getBean("address"); System.out.println(address); Car car = (Car) ctx.getBean("car"); System.out.println(car); Person person = (Person) ctx.getBean("person"); System.out.println(person); }
public class Car { private String brand; public Car(){ System.out.println("Car Constructor..."); } public void setBrand(String brand){ System.out.println("Car setter()..."); this.brand = brand; } public void init2(){ System.out.println("Car init()..."); } public void destroy(){ System.out.println("Car destroy()..."); } }xml配置
<bean id="car" class="com.cqupt.spring.cycle.Car" p:brand="Audi" init-method="init2" destroy-method="destroy"></bean>主方法:
public static void main(String[] args){ ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("cycle.xml"); Car car = (Car) ctx.getBean("car"); System.out.println("使用过程 println:"+car); ctx.close(); }输出结果:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException { System.out.println("postProessAfterInitialization... "+arg0+" "+arg1); return arg0; } @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { System.out.println("postProessBeforeInitialization... "+arg0+" "+arg1); return arg0; } }Object arg0 :就是传入进的bean实体
<bean class="com.cqupt.spring.cycle.MyBeanPostProcessor"></bean>无需指定id,IOC容器会自动加载该后置处理器的bean,不过指定了也不会出错,其实没必要指定
public static void main(String[] args){ ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("cycle.xml"); Car car = (Car) ctx.getBean("car"); System.out.println("使用过程 println:"+car); ctx.close(); }输出结果:
配置bean,我们前边一直是用的bean对应的全类名,即bean标签的属性class=“全类名”。现在使用工厂方法配置bean,分为两种:静态工厂方法、实例工厂方法。
通过定义一个静态工厂,在配置bean时,让class="静态工厂全类名",和factory-method来配置bean
定义一个Car的静态工厂:
public class StaticFactory { private static Map<String, Car> cars= new HashMap<String, Car>(); static{ cars.put("audi", new Car("audi",300000)); cars.put("Boma", new Car("Boma",400000)); } public static Car getCar(String brand){ return cars.get(brand); } }利用这个静态工厂的静态方法getCar配置bean标签的factory-method属性
<bean id="car" class="com.cqupt.spring.factory.StaticFactory" factory-method="getCar"> <constructor-arg value="Boma"></constructor-arg> </bean>使用constructor-arg子节点为静态工厂方法进行传参。
创建非静态工厂:
public class InstanceFactory { private Map<String, Car> cars; public InstanceFactory(){ cars = new HashMap<String, Car>(); cars.put("Ford", new Car("Ford",200000)); cars.put("Boma", new Car("Boma",200000)); } public Car getCar(String brand){ return cars.get(brand); } }配置工厂方法的bean,以及Car的bean
<bean id="instanceFactory" class="com.cqupt.spring.factory.InstanceFactory"></bean> <bean id="car2" factory-bean="instanceFactory" factory-method="getCar"> <constructor-arg value="Ford"></constructor-arg> </bean>使用factory-bean将工厂的bean引用,factory-method指定方法,constructor-arg传参
目前配置bean已经详述了 全类名、工厂方法两种方式,还有一种就是利用FactoryBean配置
FactoryBean是一个接口,继承此接口的类,可以用来配置bean
创建一个继承此接口的类:CarFactoryBean
public class CarFactoryBean implements FactoryBean<Car> { String brand; public void setBrand(String brand){ this.brand = brand; } @Override public Car getObject() throws Exception { return new Car("BMW",300000); } @Override public Class<Car> getObjectType() { return Car.class; } @Override public boolean isSingleton() { return true; } }继承FactoryBean接口的类都会从接口中继承三个方法:getObject 返回bean原型,getObjectType 返回bean类型,isSingleton 限定是否单利模式。
bean配置,class指向继承接口的类,property子节点时间上是配置的CarFactoryBean的属性,该bean返回的是FactoryBean的getObject方法返回的实例。
<bean id="car3" class="com.cqupt.spring.factory.CarFactoryBean" > <property name="brand" value="Ford"></property> </bean>目前只是熟悉了工厂方法,FactoryBean 配置bean,但这两种方式的功效具体在哪些方面实现,有待于深入学习,现在是觉得不如全类名配置简单。
前边讲的三种配置bean的方式:全类名,工厂方法,FactoryBean都是基于xml文件的方式,基于注解的方式配置bean也是一种常用的方式。
基于注解的方法就是在程序中,在类或者类属性的前边通过添加@形式的注解,spring会依据配置自动扫描这些添加了注解的类进入IOC容器中,IOC中的bean的默认名字就是类名第一个字母小写。
@对类进行注解有四种形式:Component,Repository,Controller,Service,这四种的区别有待于研究。
建立四个包:其他三个包是第一个的子包
com.cqupt.spring.beans.annotation
com.cqupt.spring.beans.annotation.repository
com.cqupt.spring.beans.annotation.service
com.cqupt.spring.beans.annotation.controller
在annotation包下建立一个TestObject类,并通过@Component对类进行注解
@Component public class TestObject { }
在repository包中建立UserRepository接口,注意,接口是不能进行注解的,因为接口没必要配置bean
public interface UserRepository { public void save(); }
在建立这个接口的实现类UserRepositoryImpl,对此接口进行注解,@Repository
@Repository(value="userRepository") public class UserRepositoryImpl implements UserRepository { public void save(){ System.out.println("UserRepository save..."); } }如果bean不使用默认的第一字母小写的类名,可以用上述形式指定名称,也可以去掉value。
同样在service包中创建UserService类,@Service注解
@Service public class UserService { public void add(){ System.out.println("UserService add..."); } }在controller中创建UserController包,@Controller注解
@Controller public class UserController { public void execute(){ System.out.println("UserController execute..."); } }当类建立完成并且注解之后,需要在xml中配置,使得spring依据这个配置检测注解的类,并在IOC中生成bean。
使用context:component-scan标签,base-package是指定检测的包及其子包,所以四个包都被IOC进行检测
<context:component-scan base-package="com.cqupt.spring.annotation"></context:component-scan>
主函数:
public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("beans-annotation.xml"); TestObject to= (TestObject) ctx.getBean("testObject"); System.out.println(to); UserService userService = (UserService) ctx.getBean("userService"); System.out.println(userService); userService.add(); UserController userController = (UserController) ctx.getBean("userController"); System.out.println(userController); userController.execute(); UserRepository userRepository = (UserRepository) ctx.getBean("userRepository"); System.out.println(userRepository); userRepository.save(); }输出结果:
com.cqupt.spring.annotation.TestObject@727803de
com.cqupt.spring.annotation.service.UserService@704921a5
UserService add...
com.cqupt.spring.annotation.controller.UserController@df27fae
UserController execute...
com.cqupt.spring.annotation.repository.UserRepositoryImpl@24a35978
UserRepository save...
另外:context:component-scan 标签的resource-pattern="repository/*.class"属性指定了IOC检测类的范围限定在repository包下。
<context:component-scan base-package="com.cqupt.spring.annotation" resource-pattern="repository/*.class"> </context:component-scan>
此时在Main中只能获取到UserRepository的对象,因为IOC只创建了名为userRespository的bean
通过注解机制,可以使IOC检测程序中被注解的类生产bean,但是如果不希望所以注解的类均生成bean,该如何呢?
使用范围限制:两种:一是使用resource-pattern的属性,另一种就是在context:component-scan 标签子节点context:exclude-filter排除和context:include-filter包含。
context:include-filter经常和use-default-filters="false"结合使用:表示只包含之意。
context:exclude-filter排除和context:include-filter包含这两个节点依据属性type="annotation"和type="assignable“分为两种类型:依据注解组件类型,和依据类的类型
依据组件类型的排除:
<context:component-scan base-package="com.cqupt.spring.annotation" use-default-filters="true"> <!-- 通过子节点context:exclude-filter type="annotation" 排除被IOC检测的组件类型--> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan>这样,IOC容器中不会有被Repository注解的bean,注意expression="全类名"
依据类类型的排除:
<context:component-scan base-package="com.cqupt.spring.annotation" > <context:exclude-filter type="assignable" expression="com.cqupt.spring.annotation.repository.UserRepository"></context:exclude-filter> </context:component-scan>所有继承接口UserRepository的类均不会在IOC容器中生成bean
依据类类型的包含(只包含)
<context:component-scan base-package="com.cqupt.spring.annotation" use-default-filters="false"> <context:include-filter type="assignable" expression="com.cqupt.spring.annotation.repository.UserRepository"></context:include-filter> </context:component-scan>在IOC中只有继承接口UserRepository的类才会生成bean
当然上述这些范围限定都是在类被注解的基础上的,如果类没有被注解,无论怎么包含,是annotation还是assignable,都不会生成bean
在使用基于注解配置bean时,会使用context:component-scan标签,这个标签还会自动注册一个bean后置处理器AutowiredAnnotationBeanPostProcessor,来实现自动装配bean的属性
使用注解@Autowired @Resource @Inject,最常用的是@Autowired注解
详述@Autowired使用:
使用位置,可以放在普通字段、构造器、一切具有参数的方法前
放在普通字段前:
@Controller public class UserController { @Autowired UserService userService; public void execute(){ System.out.println("UserController execute..."); userService.add(); } }
放在方法前:
@Controller public class UserController { UserService userService2; @Autowired public void setUserService2(UserService userService2) { this.userService2 = userService2; } public void execute(){ System.out.println("UserController execute..."); userService2.add(); } }@Autowired是按照兼容类型自动装配的,如果IOC中已经有生成了类型UserService的bean,不管名字是userService,还是userService2,都可以自动装配进来。
如果IOC中没有生成UserService的bean,那么程序会抛出异常。解决方法是指定@Autowired的属性required为false, @Autowired(required=false)
既然@Autowired是根据类型自动装配的,那么如果IOC中有两个以上同类型的bean的,只是bean名称不一样,就需要注解@Qualifier("beanid"),根据bean名称指定自动装配的bean,实际上在这种情况下,不指定@Qualifier,系统会自动选择名字与属性名一样的bean
@Service public class UserService { @Autowired UserRepository userRepository; public void add(){ System.out.println("UserService add..."); userRepository.save(); } }有两个UserRepository的bean
@Repository("userRepository") public class UserRepositoryImpl implements UserRepository { public void save(){ System.out.println("UserRepository save..."); } }第一个指定bean名称为userRepository
@Repository public class UserJdbcRepository implements UserRepository { @Override public void save() { System.out.println("UserJdbcRepository save..."); } }第二个没有指定,就是默认的userJdbcRepository
此时@Autowired注解的属性将默认选择名为与属性名相同的bean,即userRepository
如果第一个bean没有指定名字为userRepository
@Repository public class UserRepositoryImpl implements UserRepository { public void save(){ System.out.println("UserRepository save..."); } }那么ICO中两个bean分别是userRepositoryImpl和userJdbcRepository
就会抛出异常:Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.cqupt.spring.annotation.repository.UserRepository] is defined: expected single matching bean but found 2: userJdbcRepository,userRepositoryImpl
此时就必学添加@Qualifier注解:
@Service public class UserService { @Autowired @Qualifier("userJdbcRepository") UserRepository userRepository; public void add(){ System.out.println("UserService add..."); userRepository.save(); } }注意:也经常把@Qualifier放在方法的中:
UserRepository userRepository; @Autowired public void setUserRepository(@Qualifier("userJdbcRepository") UserRepository userRepository) { this.userRepository = userRepository; }
泛型依赖注入与普通注入的区别在于,使用了泛型,在父类之间形成注入依赖,被子类继承,子类可以自动进行依赖注入
创建两个泛型父类:BaseRepository,BaseService,BaseService的属性与BaseRepository形成依赖注入关系
public class BaseRepository<T> { }
public class BaseService<T> { @Autowired protected BaseRepository<T> repository; public void add(){ System.out.println("Service add..."); System.out.println(repository); } }创建两个父类的子类UserRepository和UserService,并注解给IOC
@Repository public class UserRepository extends BaseRepository<User> { }
@Service public class UserService extends BaseService<User> { }通过测试:
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-module.xml"); UserService us=(UserService) ctx.getBean("userService"); us.add(); }
Service add...
com.cqupt.spring.generic.di.UserRepository@5d11346a
注:注解不可以继承