- IOC
IOC,控制反转(Inversion of Control),就是把对象的创建(即bean的new操作),交给Spring来实现。
通过XML配置:bean标签是用于配置被spring容器管理的bean信息,我们可以通过bean标签,完成IOC的配置。
- 使用默认无参构造函数来创建类对象,并存入spring容器
<bean id="userService" class="com.xcj.spring.service.UserServiceImpl">bean>
public class UserServiceImpl implements UserService { }
- 静态工厂方式
<bean id="demoService" class="com.xcj.spring.factory.StaticFactory" factory-method="createDemoService">bean>
public class StaticFactory { public static DemoService createDemoService() { return new DemoServiceImpl(); } }
public class DemoServiceImpl implements DemoService { }
- 实例工厂方式
<bean id="instanceFactory" class="com.xcj.spring.factory.InstanceFactory">bean> <bean id="beanService" factory-bean="instanceFactory" factory-method="createBeanService">bean>
public class InstanceFactory { public static BeanService createBeanService() { return new BeanServiceImpl(); } }
public class BeanServiceImpl implements BeanService { }
DI,依赖注入(Dependency Injection),是spring IOC的具体实现,做的工作是Spring实例化bean对象后,对bean对象的属性信息进行赋值的操作。
依赖指的是bean实例中的属性,分为简单类型(8种基本类型和String类型)的属性、POJO类型的属性、集合数组类型的属性。
注入方式:构造器,set方法,注解,(还有使用p名称空间注入数据,本质上还是调用set方法)。
- 构造器注入
<bean id="userDemoService" class="com.xcj.spring.service.UserDemoServiceImpl"> <constructor-arg name="id" value="1">constructor-arg> <constructor-arg name="name" value="zhangsan">constructor-arg> bean>
public class UserDemoServiceImpl implements UserDemoService { private int id; private String name; public UserDemoServiceImpl(int id, String name) { this.id = id; this.name = name; } }
- set方法注入(手动装配,即XML方式)
<bean id="demoSetService" class="com.xcj.spring.service.DemoSetServiceImpl"> <property name="lists"> <list> <value>11value> <value>22value> list> property> <property name="sets"> <set> <value>111value> <value>222value> set> property> <property name="maps"> <map> <entry key="111" value="111-01"/> <entry key="222" value="222-01"/> map> property> <property name="props"> <props> <prop key="name">rootprop> <prop key="password">123456prop> props> property> bean>
public class DemoSetServiceImpl implements DemoSetService { private List
- 注解(自动装配)
(1)@Autowired,按类型注入,要唯一;如果遇到相同的,则要加上@Qualifer,表示在类型注入基础上按名称注入。
(2)@Resource,按照bean的name/id注入。
@Service("userService") public class UserServiceImpl implements UserSetService{ @Autowired private UserDao userDao; }
那么问题:Spring怎么解决循环依赖的?通过三级缓存。
循环依赖:两个或多个类之间,形成的互相引用,就是循环依赖。
- 通过构造方法的循环依赖
构造器的循环依赖,是在bean的实例化new对象时产生的,这里会发生死锁,构造器循环依赖无法解决,只能避免这种方式,尽量在设计时不出现循环依赖的问题,或者改成setter方法。
- 通过setter方法的循环依赖
setter方法的循环依赖,是在bean的实例化后,对bean属性进行填充时出现。这里需要说明,Spring中Bean需要初始化完成,才能对外使用,创建bean的过程包括实例化、属性填充、初始化、放入singletonObjects集合。
Spring解决setter方法的循环依赖是通过三级缓存解决:
查找单例bean顺序singletonObjects -> earlySingletonObjects -> singletonFactories:
先从一级缓存singletonObjects查找,如果没有且在创建中,则在二级缓存earlySingletonObjects中查找,还是找不到,且允许循环引用,则进入三级缓存singletonFactories中查找,找到会将其插入二级缓存earlySingletonObjects中,同时将其从三级缓存删除。
添加Bean顺序:
(1)new实例化后,如果一级缓存没有,则bean会存放在三级缓存singletonFactories中,并尝试删除二级缓存中可能存在的bean实例;
(2)new实例化后,如果一级和二级缓存都没有,则在三级缓存中找,找到后会放入二级缓存,并删除三级缓存存放的bean实例或代理对象。
(3)如果bean创建完成,则会直接存放在一级缓存singletonFactories,同时删除二级缓存和三级缓存。
- singletonObjects:存放完整的Bean实例。
- earlySingletonObjects:存放半成品Bean实例。
- singletonFactories:存放实例对象工厂ObjectFactory。
- AOP
AOP,面向切面编程(Aspect Oriented Programming),是一种编程范式,是OOP(面向对象编程)的延续,采用横向抽取机制,补充了OOP纵向继承体系无法解决的重复代码优化方式。
譬如,假设有A,B有相同的逻辑,我们可以横向抽取相同的部分出来,通过AOP思想和业务串联起来,同时这是可插拔式的。
AOP思想的实现一般都是基于代理模式,给业务代码进行功能增强,将业务代码和系统代码解耦。
如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类。
动态代理说明,动态代理是在运行期间,针对目标对象进行动态代理。
(1)使用XML方式实现
public class AopAdvice { public void saveLog() { System.out.println("保存日志"); } }
<bean name="aopAdvice" class="com.xcj.spring.advice.AopAdvice">bean> <aop:config> <aop:aspect ref="aopAdvice"> <aop:before method="saveLog" pointcut="execution(* com.xcj.spring..*Service.do*(..))" /> aop:aspect> aop:config>
(2)使用注解实现
@Component("aopDemoAdvice") @Aspect public class AopDemoAdvice { @Before(value="execution(* com.xcj.spring..*Service.do*(..))") public void saveLog() { System.out.println("保存日志"); } }
<context:component-scan base-package="com.xcj.spring.service">context:component-scan> <aop:aspectj-autoproxy />
使用纯注解方式,@EnableAspectJAutoproxy代替 <aop:aspectj-autoproxy /> ,@Component-scan代替 <context:component-scan>
@Configuration @ComponentScan(basePackages = "com.xcj.spring.service") @EnableAspectJAutoProxy public class SpringAOPConfiguration { }
Spring帮我们实现了事务管理的系统代码,我们可以通过配置,将业务代码与事务管理整合在一起。当然,我们也可以自己编写事务管理的代码,然后通过AOP思想组合在一起。
Spring AOP的事务支持:Spring提供了事务管理接口PlatformTransactionManager,JDBC、MyBatis等根据这个接口实现了对应的事务管理器,如DataSourceTransactionManager。
(1)XML方式
public void doSave(User user) { userDao.save(user); LogInfo logInfo = new LogInfo(); logInfo.setContent("新增User:"+user.getName); logDao.saveLog(logInfo); }
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="find*" read-only="true" /> <tx:method name="get*" read-only="true" propagation="SUPPORTS" /> <tx:method name="check*" read-only="true" propagation="SUPPORTS" /> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="do*" propagation="REQUIRED" /> <tx:method name="submit" propagation="REQUIRED"/> <tx:method name="create" propagation="REQUIRED"/> <tx:method name="ido*" propagation="REQUIRES_NEW" /> tx:attributes> tx:advice> <aop:config proxy-target-class="true"> <aop:pointcut id="txPointCut" expression="execution(* com.xcj.spring..*Service.*(..))" /> <aop:advisor id="serviceTx" pointcut-ref="txPointCut" advice-ref="txAdvice" order="1" /> aop:config>
(2)注解方式,XML配置开启事务注解,注解@Transaction。如需使用纯注解,使用@EnableTransactionManagement
<tx:annotation-driven transaction-manager="transactionManager" /> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> bean>
TODO