spring利用IOC(控制反转)机制,将创建对象的权利交给了spring框架,从而降低程序的耦合。spring有文件配置和注解两种策略来实现Bean对象的创建和注入,这两种方式可以相互代替,后面将对应记录两种方式的使用。
命名为config.xml,配置spring必要内容:
<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.xsd">
</beans>
通过调用bean所属类的带参构造器为bean的属性注入值。这也就意味着,如果需要使用构造器注入,就得为类提供包含参数的构造方法。
<!--
使用<constructor-arg>标签指定构造函数的参数以及设定的参数值
基本类型和String类型使用value赋值,引用Bean类型使用ref
同时,参数除了使用name,也可以使用index、type来指定
-->
<bean id="car" class="XMLBean.Car">
<constructor-arg name="price" value="10000"></constructor-arg>
<constructor-arg name="speed" value="80"></constructor-arg>
</bean>
<bean id="user" class="XMLBean.User">
<constructor-arg name="age" value="50"></constructor-arg>
<constructor-arg name="car" ref="car"></constructor-arg>
<constructor-arg name="name" value="周润发"></constructor-arg>
</bean>
如果需要使用set注入,那么必须要为属性提供set方法,Spring容器就是通过调用bean的set方法为属性注入值的。而在xml文件中,使用set注入的方式就是通过property标签,如下所示:
<bean id="car" class="XMLBean.Car">
<property name="price" value="10000"></property>
<property name="speed" value="80"></property>
</bean>
<bean id="user" class="XMLBean.User">
<property name="age" value="50"></property>
<property name="car" ref="car"></property>
<property name="name" value="周润发"></property>
</bean>
使用set注入一些复杂的数据类型/集合:
<!--注入集合数据/复杂数据类型:
用于List结构集合的标签:
List,set,array
用于Map结构集合的标签:
map,pro
结构相同,标签可以互换
-->
<bean id="accountDao3" class="AccountDaoImpl3">
<property name="strings">
<array>
<value>AAA</value>
<value>BBB</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
</list>
</property>
<property name="myMap">
<map>
<entry key="AAA" value="aaa"></entry>
<entry key="BBB">
<value>bbb</value>
</entry>
</map>
</property>
<property name="myProperty">
<props>
<prop key="AAA">aaa</prop>
<prop key="BBB">bbb</prop>
</props>
</property>
</bean>
静态工厂注入就是编写一个静态的工厂方法,这个工厂方法会返回我们需要的产品类,然后在配置文件中,指定使用这个工厂方法创建bean。首先需要一个静态工厂,如下所示:
public class StaticFactory {
//生产一个汽车类
public static Car getCar() {
return new Car(123, 54321);
}
}
下面需要在xml中配置car这个bean,并指定它由工厂方法进行创建:
<bean id="mycar" class="XMLBean.StaticFactory" factory-method="getCar">
</bean>
<bean id="user" class="XMLBean.User">
<property name="age" value="50"></property>
<property name="car" ref="mycar"></property>
<property name="name" value="周润发"></property>
</bean>
实例工厂与静态工厂类似,不同的是,静态工厂调用工厂方法不需要先创建工厂类的对象,因为静态方法可以直接通过类调用,所以在上面的配置文件中,并没有声明工厂类的bean。但是,实例工厂,需要有一个实例对象,才能调用它的工厂方法。先看看实例工厂的定义:
public class InstanceFactory {
/**
* 实例工厂方法,返回一个Car的实例对象
*/
public Car getCar() {
return new Car(100, 70000);
}
}
首先将实例化工厂Bean注入IOC容器中,之后注入产品bean,并指明工厂类和生产方法:
<bean id="instanceFactory" class="XMLBean.InstanceFactory">
</bean> <!--将实例化工厂bean注入-->
<!--注入产品bean,并指明工厂bean和生产方法-->
<bean id="mycar" factory-bean="instanceFactory" factory-method="getCar">
</bean>
<bean id="user" class="XMLBean.User">
<property name="age" value="50"></property>
<property name="car" ref="mycar"></property>
<property name="name" value="周润发"></property>
</bean>
public class XmlBeanTest {
@Test
public void test1() {
ApplicationContext context =
new ClassPathXmlApplicationContext("config.xml");
// 获取user这个bean
User user = context.getBean("user",User.class);
// 输出产看结果
System.out.println(user);
}
}
使用注解的好处:找到类就找到了bean注入的位置,不需要使用文件I/O,在大型系统中能够加快运行速度。
配置bean.xml文件:
<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.xsd">
<!--可以隐式地自动向Spring容器注册4个BeanPostProcessor,
这样就可以使用@ Resource 、@ PostConstruct、@ PreDestroy、@PersistenceContext、
@Autowired、@Required等注解了实现自动注入-->
<context:annotation-config/>
<!--扫描的包的位置-->
<context:component-scan base-package="包名"></context:component-scan>
</beans>
注解分为3类:
和xml配置中编写一个<bean>标签实现功能一样
@Component(value=)
作用:将当前类对象存入spring容器中
属性:value:用于指定bean的id;不写时,默认为类名首字母小写
@Controller:一般用于表现层
@Service:一般用于业务层
@Repository:一般用于持久层
以上三个注解的作用和属性与Component是一模一样的。spring提供了三层注解,使对象更佳清晰。
将User类注入IOC容器中:
@Component(value = "user") //将User类放入IOC容器中
public class User {
private String name;
private int age;
private Car car;
public User() {
}
public User(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
测试结果
可以看到@Component已经将User类注入,但是没有注入参数值。
public class AnnotationBeanTest {
@Test
public void test2() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
// 获取user这个bean
User user = context.getBean("user", User.class);
// 输出产看结果
System.out.println(user);
}
}
结果:
User{name='null', age=0, car=null}
和xml配置中<bean>标签下写一个<property>作用一样
@Autowired作用: 按照类型自动注入,只要有唯一一个bean对象类型和注入类型匹配,就可以注入成功。ps: 如果ico容器中没有任何bean对象的类型和要注入的变量类型匹配,则报错;如果有多个类型匹配时,会先匹配相同类型名称,再匹配id——@Repository(“id”)
出现位置: 可以是变量上,也可以是方法上
细节: 在使用注释注入时,可以没有set方法
@Component("car") //放入spring容器中
public class Car {
// 只包含基本数据类型的属性
private int speed;
private double price;
public Car() {
}
public Car(int speed, double price) {
this.speed = speed;
this.price = price;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"speed=" + speed +
", price=" + price +
'}';
}
}
@Component(value = "user") //放入spring容器中
public class User {
private String name;
private int age;
@Autowired //根据类型,自动找到IOC中的Car类型Bean注入
private Car car;
public User() {
}
public User(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
测试:
可以发现car不在是null,而是已经有一个初始值。这说明@Autowired已经将IOC容器中的car注入给了私有变量car。
public class AnnotationBeanTest {
@Test
public void test2() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
// 获取user这个bean
User user = context.getBean("user", User.class);
// 输出产看结果
System.out.println(user);
}
}
结果:
User{name='null', age=0, car=Car{speed=0, price=0.0}}
小结:
1.在成员变量上注入:
@Autowired //会找到spring容器中匹配的bean赋值给car
private Car car;
2.在构造函数上注入:
@Autowired //有多个参数时,注解写参数前面
public User(@Value("李连杰") String name, @Value("56") int age, @Autowired Car car) {
//"李连杰"会注入给name
//"56"会注入给age
//查找合适bean注入给car
this.name = name;
this.age = age;
this.car = car;
}
3.set注入:
@Autowired //调用set函数,将适当的bean注入给this.car
public void setCar(Car car) {
this.car = car;
}
@Qualifier作用: 在按照类型注入的基础上再按照名称注入。他在给类成员注入时不能单独使用,但是在给方法参数注入时可以。
@Autowired
@Qualifier("car")//给类成员变量注入时和@Autowired一起用
private Car car;
属性: value,用于指定bean的id
@Resourse作用:直接参照bean的id注入,可以独立使用
属性: name:用于指定bean的id
@Resource(name = "car")
private Car car;
注:以上@Autowired、@Qualifier、@Resourse三个注入只能注入其他bean类型的数据,而基本类型和String类型无法使用这些注解,另外,集合类型的注入只能用过xml的方式来实现
@value作用:用于注入基本类型和String类型的数据
属性:value:用于指定数据的值,可以使用spring中的spEL(spring的el表达式)
spEL的写法:$(表达式)
在User类中注入String和int类型的值:
//在成员变量中注入
@Value("成龙")
private String name;
@Value("60")
private int age;
//set注入
@Value("成龙")
public void setName(String name) {
this.name = name;
}
@Value("60")
public void setAge(int age) {
this.age = age;
}
<bean>标签中适用scope属性实现功能一样
@Scope
作用:用于指定bean的范围
属性:value:常取值:singleton(单例,默认) 、prototype(多例)
@PreDestroy
作用:用于指定销毁方法
@PostConstruct
作用:用于指定初始化方法
@Configuration
作用:指定当前类是一个配置类
细节:当名为Configuration类作为AnnotationConfigApplicationContext()参数时可以不添加@Configuration,否则必须要添加。
@ComponentScan
作用:通过此注解指定spring创建容器时要扫描的包
属性:value:它和basePackages的作用是一样的
@bean
作用:把当前方法的返回值作为bean对象存入spring的ioc容器中
属性:用于指定bean的id,不写时默认值是当前方法的名称
细节:当用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象,查找的方式和@Autowired注解的作用是一样的
public class SpringConfiguration {
@Bean("car") //表示将函数返回的对象放入spring容器中
public Car createCar(@Value("66") int speed, @Value("88888")double price){ //通过注解注入参数
return new Car(speed,price);
}
@Bean("user")//表示将函数返回的对象放入spring容器中
public User createUser(@Value("陈浩南") String name,@Value("33") int age,@Qualifier(value = "car") Car car){
return new User(name,age,car);
}
}
注:有了配置类,之前Car和User类前的@Component注解可以删除了。相当于已经通过配置类将响应的Bean放入了spring容器中。
测试
public class AnnotationBeanTest {
@Test
public void test2() {
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 获取user这个bean
User user = context.getBean("user", User.class);
// 输出产看结果
System.out.println(user);
}
}
结果:
User{name='陈浩南', age=33, car=Car{speed=66, price=88888.0}}
@PropertySource
作用:用于指定properties文件的位置
属性:value:指定文件名的路径和名称;关键字:classpath表示在类路径下
//jdbc.properties文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/students
jdbc.username=root
jdbc.password=1234
@ComponentScan("com")
@PropertySource("classpath:jdbcConfigeration.properties")
public class SpringConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${user}")
private String uer;
@Value("${password}")
private String password;
@Bean //将一个DataSource对象放入ioc容器
public DataSource createDatasource(){
try{
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(uer);
ds.setPassword(password);
System.out.println(driver+url+uer+password);
return ds;
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
@Import
作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解(不省略也可)。当使用@Import注解之后,有@Import注解的就是父配置类,而导入的是子配置类
属性:value[config.Class…] 用于指定配置类的字节码
@Configuration
@ComponentScan(basePackages = "com")
@Import({ JdbcConfig.class}) //导入子配置类
public class SpringConfiguration {
//...
}
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
//...
}
类对象配置总结:
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta