明白控制反转,依赖注入,面向切面编程。
控制反转(Inversion of Control)就是依赖注入(Dependency Injection)的另一个表达,意思是本来我们需要一个需要某个对象是 要什么new 什么,而控制反转是反过来先配置好资源。即资源的不同获取方式。 而面向切面编程与面向对象编程的不同在于,面向对象是把一个抽象对象包装,包装对象应该有的方法和属性。而面向切面是,我们包装的是一个事物,一个流程,比如日记记录,什么七七八八的。
环境搭建
下载好spring 包 这里我用4.0版,下载之后之后导入。
1 Bean的注入方式,Bean中如何注入另一个Bean。
package com.test; public class Car {//其中一个Bean private String factory; private double price; private int year; public String getFactory() { return factory; } public void setFactory(String factory) { this.factory = factory; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public String toString() { return "Car [factory=" + factory + ", price=" + price + ", year=" + year + "]"; } public Car(String factory, double price, int year) { super(); this.factory = factory; this.price = price; this.year = year; } public Car (){}//使用参数构造bean必须提供无参数构造模式,不然会报错。 public Car(String factory, double price) { super(); this.factory = factory; this.price = price; } public Car(String factory, int year) { super(); this.factory = factory; this.year = year; } } package com.test; public class Person {//bean中带bean private String name; private int age; private 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; } public Person() { } public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } } package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main {//测试类 public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");//在工程目录下读取bean的配置。 Car car = (Car)context.getBean("car1");//根据bean配置的ID进行配置 System.out.println(car); // Car car = context.getBean(Car.class); //这是直接根据类的配置,缺点是当我们有两个同样的Car的时候,会不知道读取哪一出 导致出错。 Car car2 = (Car)context.getBean("car2"); System.out.println(car2); Car car3 = (Car)context.getBean("car3"); System.out.println(car3); Car car4 = (Car)context.getBean("car4"); System.out.println(car4); Person p1 = (Person)context.getBean("person1"); System.out.println(p1); Person p2 = (Person)context.getBean("person2"); System.out.println(p2); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="car1" class="com.test.Car" > <property name = "factory" value="futor"/> <property name = "price" value="2000"/> <property name = "year" value="5"/> </bean> <bean id="car2" class="com.test.Car" > <constructor-arg value = "aodu"></constructor-arg> <constructor-arg value = "50000"></constructor-arg> <constructor-arg value = "4"></constructor-arg> </bean> <!-- 以下两个bean,需要指定参数类型,避免bean不知道你要加载的构造模式是哪个,因为参数类型构造不能重复,以及特殊字符比如<>如何写 --> <bean id="car3" class="com.test.Car" > <constructor-arg > <value><![CDATA[<>auto]]></value> </constructor-arg> <constructor-arg value = "50000" type="double"></constructor-arg> </bean> <bean id="car4" class="com.test.Car" > <constructor-arg value = "aodu" type="java.lang.String"></constructor-arg> <constructor-arg value = "5" type="int"></constructor-arg> </bean> <!-- 参数里面的Bean应用用ref字符,内部构造的bean外部不能使用 --> <bean id ="person1" class="com.test.Person"> <property name="name" value="xiaozhi"></property> <property name="age" value ="21"></property> <property name="car" ref="car1"></property> </bean> <bean id ="person2" class="com.test.Person"> <property name="name" value="xiaozhi"></property> <property name="age" value ="21"></property> <property name="car"> <bean class="com.test.Car"> <constructor-arg value = "aotuo"></constructor-arg> <constructor-arg value = "80000"></constructor-arg> <constructor-arg value = "8"></constructor-arg> </bean> </property> </bean> </beans>
上面是一个文件名为Bean的xml配置文件
级联属性要赋值需要先有初始化。stuct2会自动创建然后赋值上。
集合属性赋值,list,导入util命名空间可以独立实例化。
map属性 用entry key和value-ref
以及properties 用props 配置prop 全都key
以及使用p 来进行赋值
代码区
package com.test; import java.util.List; public class NewPerson { private String name; private int age; private List<Car>cars; 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 List<Car> getCars() { return cars; } public void setCars(List<Car> cars) { this.cars = cars; } public NewPerson(){} @Override public String toString() { return "NewPerson [name=" + name + ", age=" + age + ", cars=" + cars + "]"; } } package com.test; import java.util.Map; public class OldPerson { private String name; private int age; private Map<String,Car> cars; 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 Map<String, Car> getCars() { return cars; } public void setCars(Map<String, Car> cars) { this.cars = cars; } public OldPerson(){} @Override public String toString() { return "OldPerson [name=" + name + ", age=" + age + ", cars=" + cars + "]"; } } package com.test; import java.util.Properties; public class DataSource { private Properties properties; public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "DataSource [properties=" + properties + "]"; } } 测试代码 package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");//在工程目录下读取bean的配置。 NewPerson np = (NewPerson) context.getBean("newperson1"); System.out.println(np); NewPerson np2 = (NewPerson) context.getBean("newperson2"); System.out.println(np2); OldPerson op=(OldPerson) context.getBean("oldperson1"); System.out.println(op); DataSource ds=(DataSource) context.getBean("datasource1"); System.out.println(ds); Person p =(Person) context.getBean("personp");//利用P标签来实例化 System.out.println(p); Person p2 =(Person) context.getBean("personp2");//利用自动装配来实例化 System.out.println(p2); } }
xm添加代码
<!-- 用 list表示list数组 --> <bean id="newperson1" class="com.test.NewPerson"> <property name="name" value="小智"></property> <property name="age" value="45"></property> <property name="cars"> <list> <ref bean="car1"/> <ref bean="car2"/> <ref bean="car3"/> </list> </property> </bean> <!-- 可以用util:list来独立实例化,这样需要的bean都能用到 比如下面的newpersons --> <util:list id="cars1"> <ref bean="car1"/> <ref bean="car2"/> <ref bean="car3"/> </util:list> <bean id="newperson2" class="com.test.NewPerson"> <property name="name" value="小盛"></property> <property name="age" value="45"></property> <property name="cars" ref="cars1"></property> </bean> <!-- map的使用方式 --> <bean id="oldperson1" class="com.test.OldPerson"> <property name="name" value="小红"></property> <property name="age" value="45"></property> <property name="cars"> <map> <entry key="名字一" value-ref="car1"></entry> <entry key="名字二" value-ref="car2"></entry> <entry key="名字三" value-ref="car3"></entry> </map> </property> </bean> <!-- 常见的集合类,可以用来存储用户密码等等 --> <bean id="datasource1" class="com.test.DataSource"> <property name="properties"> <props> <prop key="UserName">无名</prop> <prop key="PassWord">1123456789</prop> <prop key="DatabaseDriver">www.sql.driver.link</prop> </props> </property> </bean> <!-- 这是利用 p 标签来在bean中设置属性,记得开头填写标签 --> <bean id="personp" class="com.test.Person" p:age="10" p:name="cool" p:car-ref="car1"></bean> <!-- 自动装配byName 则在setter方法名字一样装配,byType则根据类型,但是必须唯一 --> <!-- 缺点多 整合框架会用到 --> <bean id="personp2" class="com.test.Person" p:age="10" p:name="cool" autowire="byName"></bean>
Bean之间的关系
继承关系parent
继承的父类里面的信息可以被子类重写,autowire 不能继承,可以专门写一个abstract的类来当抽象类,但是abstract类不能被实例化
依赖关系depends-on
依赖于某物的意思,必须有某物才能这个实例,但是内容不一定要用某物
package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");//在工程目录下读取bean的配置。 Person p3 =(Person) context.getBean("pperson");//继承关系 System.out.println(p3); Person p4 =(Person) context.getBean("persond");//依赖关系 System.out.println(p4); } }
bean文件添加
<!-- 继承关系,重写,autowire不能重写。但是abstract 设置为true就不能实例化 --> <bean id="persons" class="com.test.Person" p:name="xiaoxiaozhi" p:age="88" abstract="true"></bean> <bean id="pperson" parent="persons" name="小智"></bean> <!-- 依赖关系 depends-on ,依赖于cardpend的意思,必须有cardpend才能这个实例,但是内容不一定要用cardpend --> <bean id = "cardepend" class="com.test.Car" p:factory="hongjing" p:price="888" p:year="5"></bean> <bean id="persond" parent="persons" depends-on="cardepend" p:car-ref="cardepend"></bean>
Bean的作用域
bean是默认单例模式 即Singleton 但是可以修改成原型模式,原型模式是prototype,单例模式是在获取容器IoC构造的时候就构造好,而原型模式是我们之后需要的时候才构造,以下代码测试
package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");//在工程目录下读取bean的配置。 Car car1= (Car) context.getBean("carsingle"); Car car2= (Car) context.getBean("carsingle"); Car car3= (Car) context.getBean("carproto"); Car car4= (Car) context.getBean("carproto"); System.out.println(car1==car2); System.out.println(car3==car4); //这段代码将会输出 true false ,原因是在默认的单例模式下,car1和car2都是单例的引用,而在原型模式下 //car3和car4是相当于需要的时候才创建,如果给car构造函数一个简单输出,会发现,在 ApplicationContext //装配好的时候就已经构造好单例模式,而原型模式是在创建好的时候才构造好。 } }
添加的bean
<!--默认是singleton,可以改成原型。--> <bean id="carsingle" class="com.test.Car" p:factory="audi" p:price="5000" p:year="5" scope="singleton"></bean> <bean id="carproto" class="com.test.Car" p:factory="audi" p:price="5000" p:year="5" scope="prototype"></bean>
PropertyPlaceholderConfigurer 是 BeanFactory 后置处理器的实现,也是 BeanFactoryPostProcessor 接口的一个实现。允许将上下文(配置文件)中的属性值放在另一个单独的标准 JavaProperties 文件中去。在 XML 文件中用类似 EL 表达式的 ${key} 替换指定的 properties 文件中的值。这样的话,以后更改参数时,我们直接替换 properties 文件中的值就可以了。
一些关键参数的设置就可以放在xxx.properties 里面,因为bean很多,可以很便捷。
package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");//在工程目录下读取bean的配置。 Database db = (Database) context.getBean("database"); System.out.println(db.getName()); //成功输出root } } package com.test; public class Database {//假设这是我们要配置的database private String name; private String password; private String url; private String driver; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } }
bean添加
<!--使用Beanfactory的后置处理器,就需要添加对应的标签 context 后面的value属性用"${xx}" 配置文件的名字--> <context:property-placeholder location="classpath:db.properties"/> <bean id="database" class="com.test.Database"> <property name="name" value="${name}"></property> <property name="password" value="${password}"></property> <property name="url" value="${url}"></property> <property name="driver" value="${driver}"></property>
对应的 db.properties文件是
name=root
password=123456
url=jdbc
driver=jdbc.driver