IOC:(Inversion(反转) Of Control):控制反转
DI:(Dependency Injection)依赖注入
<!--一个Bean标签可以注册一个组件(类、对象)--> <!-- class:组件的全类名 id:唯一标识 --> <bean id="person1" class="com.bean.Person"> <!--使用property标签为Person对象的属性赋值--> <!-- name="" : 指定属性名 value="" :指定属性的值--> <property name="personName" value="张三" ></property> <property name="personAge" value="18" ></property> </bean> 复制代码
public void test(){ //ApplicationContext 代表ioc容器 //ClassPathXmlApplicationContext:当前应用的xml配置文件在ClassPath下 //根据配置文件得到ioc容器对象 ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); Person person = (Person)ioc.getBean("person1"); } 复制代码
<bean id="person1" class="com.bean.Person"> <property name="personName" value="张三" ></property> <property name="personAge" value="18" ></property> </bean> <bean id="person2" class="com.bean.Person"> <property name="personName" value="小花" ></property> <property name="personAge" value="18" ></property> </bean> 复制代码
public void test(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); //如果ioc容器中这个类型的bean有多个,查找就会报错 Person person = ioc.getBean(Person.class); //这样使用 即便ioc容器中这个类型的bean有多个,查找也不会报错 Person person = ioc.getBean("person1",Person.class); } 复制代码
<bean id="person1" class="com.bean.Person"> <constructor-arg name="personName" value="张三"></constructor-arg> <constructor-arg name="personAge" value="18"></constructor-arg> <!--此处可以省略name属性,但需要按照构造器参数的顺序指定value值--> <constructor-arg value="张三"></constructor-arg> <constructor-arg value="18"></constructor-arg> <!--index="0" 为参数指定索引 从0开始--> <constructor-arg value="张三" index="0"></constructor-arg> <constructor-arg value="18" index="1"></constructor-arg> <!--如果有多个有参构造器 使用type指定参数类型--> <constructor-arg value="张三" index="0"></constructor-arg> <constructor-arg value="18" index="1" type="java.lang.Integer"></constructor-arg> </bean> 复制代码
public void test(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); Person person = ioc.getBean("person1"); } 复制代码
名称空间:在xml中名称空间是用来防止标签重复的
<!--使用p名称空间赋值时,需先导入p名称空间--> <bean id="person1" class="com.bean.Person" p:personName="张三" p:personAge="18"> </bean> 复制代码
//实体类 public class Person{ private String name; private int age; private Car car;//Car是一个实体类 private List<Book> books;//Book是一个实体类 private Map<String,Object> maps; private Properties properties; } 复制代码
<bean id="car" class="com.bean.Car"> <property name="carNmae" value="宝马"></property> </bean> <bean id="book" class="com.bean.Book"> <property name="bookNmae" value="西游记"></property> </bean> <bean id="person1" class="com.bean.Person"> <!--赋值为null--> <property name="name"> <null/> </property> <!--ref="car" 这是一个严格的引用 person中的car跟 直接从容器中获取的car是一样的--> <property name="car" ref="car"></property> <!--为list类型赋值--> <property name="books"> <list> <!--内部bean 写id和不写id是一样的 外部获取不到--> <bean id="book" class="com.bean.Book" p:bookName="西游记"></bean> <ref bean="book"/> </list> </property> <!--为map类型赋值--> <bean id="maps"> <!--底层用的是LinkedHashMap--> <map> <!--一个entry代表一个键值对--> <entry key="key1"value="value1"></entry> <entry key="key2"value="value2"></entry> <entry key="key3"value-ref="book"></entry> <entry key="key4"> <!--内部bean无法用id获取 无论是否有id--> <bean id="" class="com.bean.Car"> <property name="carName" value="宝马"></property> </bean> </entry> </map> </bean> <!--为Properties类型赋值--> <bean name="properties"> <!--properties 里面 所有的k=v都是String类型--> <props> <prop key="username">root</prop> <prop key="username">123456</prop> </props> </bean> </bean> 复制代码
<bean id="car01" class="cam.bean.Car"> <property name="carName" value="宝马"></property> </bean> <bean id="person" class="cam.bean.Person"> <property name="car" ref="car01"></property> <property name="car.carName" value="奔驰"></property> </bean> 复制代码
<bean id="person1" class="com.bean.Person"> <property name="perName" value="张三"></property> <property name="perAge" value="15"></property> <property name="perGender" value="男"></property> </bean> <!--parent="" : 指定当前的bean的配置信息继承于哪个bean class=""可以省略不写 --> <bean id="person2" class="com.bean.Person" parent="person1"> <property name="perName" value="张三"></property> </bean> <!--abstract="true" 表示这个bean只能被继承 不可以获取--> <bean id="person3" class="com.bean.Person" parent="person1" abstract="true"> <property name="perGender" value="男"></property> </bean> 复制代码
<!--原来是按照配置的顺序创建bean--> <bean id="person" class="com.bean.Person"></bean> <bean id="car" class="com.bean.Car"></bean> <bean id="book" class="com.bean.Book"></bean> <!-- depends-on="car,book" 改变bean的创建顺序--> <bean id="person" class="com.bean.Person" depends-on="car,book"></bean> <bean id="car" class="com.bean.Car"></bean> <bean id="book" class="com.bean.Book"></bean> 复制代码
<bean id="book" class="com.bean.Book" scope=""></bean> 复制代码
scope="" 设置作用域 默认所有的bean都是单实例的
静态工厂:工厂本身不用创建对象,通过静态方法调用,对象 = 工厂类.工厂方法名();
public class AirPlaneStaticFactory{ //这个方法是静态方法 public static AirPlane getAirPlane(String planeName){ AirPlane airplane = new AirPlane(); airplane.setPlaneName(planeName); return airPlane; } } 复制代码
<!--静态工厂(不需要创建工厂本身) 1.class指定静态工厂全类名, 2.factory-method 指定工厂方法, 3.constructor-arg 可以为方法传参 --> <bean id="airPlane" class="com.factory.AirPlaneStaticFactory" factory-method="getAirPlane"> <constructor-arg name="planeName" value="大飞机1号" ></constructor-arg> </bean> 复制代码
public void test(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); //获取到的是飞机 并不是工厂 AirPlane airplane = ioc.getBean("airPlane"); } 复制代码
**实例工厂:**工厂本身需要创建对象,
工厂类 工厂对象 = new 工厂类();
对象 =工厂对象.工厂方法名();
public class AirPlaneInstanceFactory{ //这个方法不是静态方法 public AirPlane getAirPlane(String planeName){ AirPlane airplane = new AirPlane(); airplane.setPlaneName(planeName); return airPlane; } } 复制代码
<!--实例工厂(需要创建工厂本身)--> <bean id="airPlaneInstanceFactory" class="com.factory.AirPlaneInstanceFactory"> </bean> <!--factory-bean="" 指定当前对象由哪个工厂创建 factory-method=""指定工厂方法--> <bean id="airPlane" class="com.bean.AirPlane" factory-bean="airPlaneInstanceFactory" factory-method="getAirPlane"> <constructor-arg name="planeName" value="大飞机2号" ></constructor-arg> </bean> 复制代码
public void test(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); //获取到的是飞机 并不是工厂 AirPlane airplane = ioc.getBean("airPlane"); } 复制代码
public class MyFactoryBeanImpl implements FactoryBean<Book>{ //getObject:工厂方法 返回创建的对象 @Override public Book getObject() throws Exception{ Book book = new Book(); book.setId(1); return book; } //返回 创建的对象的类型 @Override public Class<?> getObjectType(){ return Book.class; } //返回 是否是单例 //false : 不是单例 true: 是单例 @Override public boolean isSingleton(){ return false; } } 复制代码
<!-- 注意!:无论 isSingleton()这个方法返回值是什么 ioc容器启动的时候不会创建这个实例--> <bean id="myFactoryBeanImpl" class="com.factory.MyFactoryBeanImpl"></bean> 复制代码
**注意 获取到的是book对象 **
public void test(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); //获取到的是book对象 Book book = ioc.getBean("myFactoryBeanImpl"); } 复制代码
<bean id="book" class="com.bean.Book" destory-method="" init-method="" > </bean> 复制代码
<bean id="book" class="com.bean.Book" destory-method="" init-method="" scope="protorype" > </bean> 复制代码
数据库链接池作为单实例是最好的,一个项目就一个连接池,连接池里面管理很多链接,链接是直接从链接池里面拿
可以让Spring帮我们创建连接池对象 管理连接池
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="root"></property> <property name="password" value="123456"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> </bean> 复制代码
jdbc.properties
#username=root jdbc.username=root jdbc.password=123456 jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test jdbc.driverClass=com.mysql.jdbc.Driver 复制代码
在ApplicationContext.xml中配置时 需要引入context命名空间
<!--加载外部配置文件的 classpath: 表示引用类路径下的配置文件--> <context:property-placeholder location="classpath:jdbc.properties" /> <!--username 是spring中的一个关键字 在这里不可以使用username--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!--<property name="user" value="${username}"></property>--> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> </bean> 复制代码
**注意!自动装配仅限于自定义类型的属性 **
<bean id="car" class="com.bean.Car"> <property name="carName" value="宝马"></property> <property name="color" value="白色"></property> </bean> <!-- autowire="" default/no:不自动装配,不自动为car属性赋值 byName:以属性名作为id去容器中找到一个组件,给他赋值,如果找不到就赋值null byType:以属性的类型作为查找依据去容器中找到这个组件,如果容器中有多个这样的类型会报错 constructor:按照有参构造器为car赋值 1.先按照有参构造器参数类型进行装配,没有就直接为组件装配null 2.如果按照类型找到了多个bean:以参数的名作为id继续装配,找不到就null 假设有一个List<Book> books属性,容器可以把容器中所有的book封装进list --> <bean id="person" class="com.bean.Person" autowire="default"></bean> 复制代码
<bean id="car" class="com.bean.Person"> <property name="carName" value="宝马"></property> </bean> <bean id="person" class="com.bean.Person"> <property name="age" value="#{12*5}"></property> <property name="perName" value="#{car.carName}"></property> <property name="car" value="#{car}"></property> <property name="email" value="#{T(java.util.UUID).randomUUID().toString()}"></property> <property name="testName" value="#{car.getCarName()}"></property> </bean> 复制代码
给要添加的组件上标上以上四个注解之一
告诉spring,自动扫描加了注解的组件,依赖context命名空间
<!--自动组件扫描--> <!--base-package="" 指定扫描的基础包--> <context:component-scan base-package=""></context:component-scan> 复制代码
type="annotation":按照注解进行排除-->标注了指定注解的组建不要
expression="":注解的全类名
type="assignable":按照类进行排除
expression="":类的全类名
type="aspectj":aspectj表达式(很少用)
type="custom":自定义一个TypeFilter;自己写代码决定哪些使用(很少用)
type="regex":正则表达式(很少用)
<context:component-scan base-package=""> <!--表示标注了@controller的注解不进行扫描--> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--表示com.controller.BookController这个类不进行扫描--> <context:exclude-filter type="assignable" expression="com.controller.BookController"/> </context:component-scan> 复制代码
type="annotation":按照注解进行排除-->标注了指定注解的组建不要
expression="":注解的全类名
type="assignable":按照类进行排除
expression="":类的全类名
type="aspectj":aspectj表达式(很少用)
type="custom":自定义一个TypeFilter;自己写代码决定哪些使用(很少用)
type="regex":正则表达式(很少用)
<context:component-scan base-package="" use-default-filters="true"> <!--表示只有标注了@controller的注解进行扫描--> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--表示只有com.controller.BookController这个类进行扫描--> <context:include-filter type="assignable" expression="com.controller.BookController"/> </context:component-scan> 复制代码
这里bean的id默认就是类名首字母小写
使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的:
public void test(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); Object bean = ioc.getBean(""); } 复制代码
@Repository("你想要的id名") 四个注解都是一样的 复制代码
@Scope(value="prototype") 复制代码
@Autowired为bookservice自动赋值
@Controller public class BookServlet{ @Autowired private BookService bookService; } 复制代码
先 按照类型 去容器中找到对应的组件;bookService = ioc.getBean("BookService.class");
@Autowired public void methods(@Qualifier("newbookservice")BookService bookservice){ System.out.println("") } 复制代码
导包 导入spring-test-4.0.0
@ContextConfiguration使用这个注解来指定spring的配置文件的位置
@RunWith()指定用哪种驱动进行单元测试。默认就是junit
@RunWith(SpringJUnit4ClassRunner.class)
使用spring的单元测试模块来执行标注了@Test注解的测试方法
以前的@Test只是由JUnit执行
@ContextConfiguration(locations="classpath:spring.xml") @RunWith(SpringJUnit4ClassRunner.class) public class SpringTest{ ApplicationContext ac = null; @Autowired BookServlet bookServlet; } 复制代码
public abstract class BaseDao<T>{ public abstract void save(); ... } 复制代码
@Repository public class BookDao extends BaseDao<Book>{ @Override public void save(){ ... } ... } 复制代码
@Repository public class UserDao extends BaseDao<User>{ @Override public void save(){ ... } ... } 复制代码
@Service public class BookService extends BaseService<Book>{ ... } 复制代码
@Service public class UserService extends BaseService<User>{ ... } 复制代码
public class BaseService<T>{ @Autowired private BaseDao<T> baseDao; public void test(){ baseDao.save(); } ... } 复制代码
@Test public void test() { ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml"); BookService bookService = ioc.getBean(BookService.class); bookService.test(); } 复制代码