Spring IOC和AOP理解,以及怎么解决循环依赖

  • 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 lists;

    private Set sets;

    private Map maps;

    private Properties props;

    public void setLists(List lists) {
        this.lists = lists;
    }

    public void setSets(Set sets) {
        this.sets = sets;
    }

    public void setMaps(Map maps) {
        this.maps = maps;
    }

    public void setProps(Properties props) {
        this.props = props;
    }

} 
  
 

 

  • 注解(自动装配)

(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

 

你可能感兴趣的:(Spring IOC和AOP理解,以及怎么解决循环依赖)