依赖注入(DI)&Aop实践

Spring

Spring是一个轻量级的DI和AOP容器框架

IoC (Inversion of Control)

控制反转,控制反转是通过依赖注入实现的,把一个类交给spring管理,是一个盛满Bean的spring容器。

DI(Dependency Injection)

依赖注入:依赖注入的主要目的是为了解耦,体现了组合关系,是容器负责创建对象和维护对象之间的关系,而不是同过对象本身创建和解决自身的依赖

依赖注入(DI)的实现

依赖注入有三种方式实现,set注入(设值注入),构造器注入,接口注入,Spring支持setter注入,构造器注入,set注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

构造器注入

指 IoC 容器使用构造方法注入被依赖的实例。基于构造器的 DI 通过调用带参数的构造方法实现,每个参数代表一个依赖。
构造器有三种注入方式:索引注入,参数名称注入,类型注入

//类一
public class HelloBean {
}
//类二
public class MyBean {
    private  Long id;
    private  String name;
    private  String length;
    private  HelloBean hb;
    //有参构造器
    public MyBean(Long id, String name, String length, HelloBean hb) {
        this.id = id;
        this.name = name;
        this.length = length;
        this.hb = hb;
    }
    public MyBean(){}
    @Override
    public String toString() {
        return "MyBean{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", length='" + length + '\'' +
                ", hb=" + hb +
                '}';
    }
}
//测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestDIConstructor {
    @Autowired
    private MyBean myBean;
    @Test
    public void testName() throws Exception {
         System.out.println(myBean);
     }
}
测试结果:MyBean{id=1, name='他们', length='十八', hb=cn.itsource._01ConstructorDI.HelloBean@7fc229ab}
<!-- (1)通过构造器索引index 注入-->
        <constructor-arg index="0" value="1"></constructor-arg>
        <constructor-arg index="1" value="哈哈"></constructor-arg>
        <constructor-arg index="2" value="18"></constructor-arg>
        <constructor-arg index="3" >
            <bean name="helloBean" class="cn.itsource._01ConstructorDI.HelloBean"></bean>
        </constructor-arg>
<!-- (  <!--(2)通过构造器参数名称 常用-->
       <constructor-arg name="id" value="1"></constructor-arg>
       <constructor-arg name="name" value="haha"></constructor-arg>
       <constructor-arg name="length" value="20"></constructor-arg>
       <constructor-arg name="hb" ref="helloBean"></constructor-arg>
       <bean name="helloBean" class="cn.itsource._01ConstructorDI.HelloBean"></bean>
<!--  <constructor-arg type="java.lang.Long" value="1"></constructor-arg>
      <constructor-arg type="java.lang.String" value="他们"></constructor-arg>
      <constructor-arg type="java.lang.String" value="十八"></constructor-arg>
      <constructor-arg  name="hb" ref="helloBean"></constructor-arg>
  </bean>
  <bean name="helloBean" class="cn.itsource._01ConstructorDI.HelloBean"></bean>

属性注入

指 IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 bean 后,调用该 bean 的 setter 方法,即可实现基于 setter 的 DI。

//类一
public class HelloBean {   
}
//类二
public class MyBean {
   //最常用就是普通属性
   private Long id;
   private String name;
   //数组方式注入
   private String[] arrays;
   //List/Set
   private List<String> list;
   private Set<String> set;
   private List<HelloBean> helloBeanList;
   private Set<HelloBean> helloBeanSet;
   //Map
   private Map<String,String> hp ;
   //properties --HashTable 子类 特殊属性 jdbc.properites driverClassName=xxxx 写到该对象
   private Properties prop1;
   private Properties prop2;
  ··· 省略了对应的set/get方法
  //测试类:
  @RunWith(SpringJUnit4ClassRunner.class)
  @ContextConfiguration("classpath:applicationContext.xml")
public class TestSetterDI {
   @Autowired
   private MyBean myBean;
   @Test
   public void testName() throws Exception {
        System.out.println(myBean);
    }
}
测试类结果:MyBean{id=2, name='huhu', arrays=[A, B, C], list=[list集合1, list集合2, list集合3], set=[set集合1, set集合2, set集合3], helloBeanList=[cn.itsource._02SetterDI.HelloBean@6b4a4e18, cn.itsource._02SetterDI.HelloBean@27c86f2d, cn.itsource._02SetterDI.HelloBean@2c34f934, cn.itsource._02SetterDI.HelloBean@2c34f934], helloBeanSet=[cn.itsource._02SetterDI.HelloBean@2893de87, cn.itsource._02SetterDI.HelloBean@55ca8de8, cn.itsource._02SetterDI.HelloBean@2c34f934], hp={name=a行, pw=123456}, prop1={driverClassName=com.mysql.jdbc.Driver, username=qiang?}, prop2={driverClassName=com.mysql.jdbc.Driver, username=qiang强}}

//配置信息

 <bean name="myBean" class="cn.itsource._02SetterDI.MyBean">
       <!--属性注入-->
       <property name="id" value="2"></property>
       <property name="name" value="huhu"></property>
       <!--数组注入-->
       <property name="arrays" value="A,B,C"></property>
       <property name="list">
          <list>
              <value>list集合1</value>
              <value>list集合2</value>
              <value>list集合3</value>
          </list>
       </property>
       <property name="set">
           <set>
               <value>set集合1</value>
               <value>set集合2</value>
               <value>set集合3</value>
           </set>
       </property>
       <property name="helloBeanSet">
           <set>
               <bean class="cn.itsource._02SetterDI.HelloBean" />
               <bean class=" cn.itsource._02SetterDI.HelloBean"/>
               <ref bean="helloBean"/>
               <ref bean="helloBean" />
           </set>
       </property>
       <property name="helloBeanList">
           <list>
               <!--获取三个对象,其中前两个是属性中创建的,后面两个是引入的-->
               <bean class="cn.itsource._02SetterDI.HelloBean" />
               <bean class=" cn.itsource._02SetterDI.HelloBean"/>
               <ref bean="helloBean" />
               <ref bean="helloBean" />
           </list>
       </property>
       <!--Map属性存值-->
       <property name="hp">
           <props >
               <prop key="name">a行</prop>
               <prop key="pw">123456</prop>
           </props>
       </property>
       <!--不支持中文-->
       <property name="prop1">
           <value>
               driverClassName=com.mysql.jdbc.Driver
               username=qiang强
           </value>
       </property>
       <!--支持中文-->
       <property name="prop2">
           <props>
               <prop key="driverClassName">com.mysql.jdbc.Driver</prop>
               <prop key="username">qiang强</prop>
           </props>
       </property>
   </bean>
    <bean name="helloBean" class="cn.itsource._02SetterDI.HelloBean"></bean>

自动匹配XMl配置

@Autowrie注解默认是以类型来匹配,默认情况下必须要求依赖对象必须存在,当有两个相同类型的bean时,会出现匹配错误,解决方案:给相同的bean设置不同的name,同时指定它匹配的名字

 <!-- 
        default-autowire="byType"默认以类型来装配
        byName:  通过bean的名称注入
        byType:通过类型  如果一个有两个bean 都指相同一个类型的时候,就会报错 不能通过类型注入
               可以通过名称注入
   -->
    <bean name="userDao" class="cn.itsource._03AutoXml.UserDao"  ></bean>
    <!--两个相同类型的serviceBean-->
    <bean name="userService" class="cn.itsource._03AutoXml.UserServiceImpl" ></bean>
    <bean name="userService1" class="cn.itsource._03AutoXml.UserServiceImpl" ></bean>
    <!--以name来匹配-->
    <bean name="userController" class="cn.itsource._03AutoXml.UserController"  autowire="byName"></bean>

全注解自动注入

Dao层使用@Repository
Service使用@Service
Controller使用@Controller
当一个接口有多个实现类的时侯,可以通过名字去区分
有两种自动装配方式@Autowrie、@Resource

@Service
public class UserService  implements IUserService{
      //方案一:一个接口有多个实现的情况下面 通过名字去区分
    //方案二:通过Resource这个注解
    //区别:@Autowired和@Qualifier 都是属于spring的注解 ,
    //      Resource使用jdk的注解 推荐使用Autowired和Qualifier,可以和spring进行无缝衔接
    //      autowired默认是根据类型匹配,如果类型匹配不上在根据名字匹配
    //      而Resource默认根据名字匹配,名字匹配不上就匹配类型
    //@Resource(name = "jdbcUserDao")等同于
    @Autowired
    @Qualifier(value = "jpaUserDao")
    private IUserDao userDao;
    public void save() {
        userDao.save();
    }
}

自动装配属性注解:

@Autowired与@Resource异同:
1° @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2° @Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属 性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。
3° @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上 时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配 。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

AOP(面向切面编程)

AOP(面向切面编程)目的是为了解耦,AOP可以让一组类共享相同的行为,是OOP(Object 面向对象编程)的补充和完善
Spring实现Aop有两种方案:JDK代理模式与CGLIB代理模式

Spring实现Aop方案:

若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理
若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类

手动配置Aop注解

<!--添加aop命名空间-->
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

Aop增强

 <!--
        扫描注解:
        @Component, @Repository, @Service,@Controller
    -->
   <context:component-scan base-package="cn.itsource._05AOPXml"></context:component-scan>
    <!--配置通知-->
    <aop:config >
        <aop:pointcut id="pointcut" expression="execution(* cn.itsource._05AOPXml.I*Service.*(..))"></aop:pointcut>
        <aop:aspect ref="txManager">
            <!--前置通知-->
           <!-- <aop:before method="begin" pointcut-ref="pointcut"></aop:before>
            //后置通知
            <aop:after method="commit" pointcut-ref="pointcut"></aop:after>
            //最终通知
            <aop:after-returning method="close" pointcut-ref="pointcut"></aop:after-returning>
            //异常通知
            <aop:after-throwing method="rollback" throwing="e" pointcut-ref="pointcut"></aop:after-throwing>-->
            <aop:around method="around" pointcut-ref="pointcut"></aop:around>
        </aop:aspect>
    </aop:config>
    <bean name="txManager" class="cn.itsource._05AOPXml.TxManager"></bean>

事务管理类:没有使用环绕增强的时候,另外四个增强需要给它们加上切点

//事务管理类
public class TxManager {
   /* @Pointcut//当不用环绕增加时,需要添加切点
    public void pointCut(){
    }*/
    public void begin(){
        System.out.println("开启事务");
    }
    public void commit(){
        System.out.println("提交事务");
    }
    public void close(){
        System.out.println("关闭");
    }
    //所有的异常的父类
    public void rollback(Throwable e){
        System.out.println("回滚事务"+e.getMessage());
    }
    //环绕通知
    public void around(ProceedingJoinPoint joinPoint){
        try {
            begin();
            //调用方法
            joinPoint.proceed();
            commit();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }finally{
            close();
        }
    }
}

Aop全注解实现(动态代理)

开启代理模式
<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>

 <!--
        扫描注解:
        @Component, @Repository, @Service,@Controller
    -->
   <context:component-scan base-package="cn.itsource._06AOPAnnotation"></context:component-scan>
    <!--开启代理模式-->
    <aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
/事务管理类
@Component//不用三层注解的时候,使用component注解
@Aspect//声明这个面是个切面
public class TxManager {
 //在service接口中执行切点
 @Pointcut("execution(* cn.itsource._06AOPAnnotation.I*Service.*(..))")
 public void pointcut(){

 }
 //前置通知
 //@Before("pointcut()")
 public void begin(){
      System.out.println("开始事务");
 }
 //后置通知
 // @After("pointcut()")
 public void commit(){
     System.out.println("提交事务");
 }
 //最终通知
 //@AfterReturning("pointcut()")
 public void close(){
     System.out.println("关闭");
 }
 //所有的异常的父类,异常通知
  //@AfterThrowing(value = "pointcut()",throwing = "e")
 public void rollback(Throwable e){
     System.out.println("回滚事务"+e.getMessage());
 }
 //环绕通知,使用环绕通知时,得取消其他方法的注解
 @Around("pointcut()")
 public void around(ProceedingJoinPoint joinPoint){
     try{
         begin();
         //执行方法
         joinPoint.proceed();
         commit();
     }catch (Throwable throwable){
         throwable.printStackTrace();
     }finally {
         close();
     }
 }
}

获取Bean对象的方式

1.使用无参构造方法获取

<bean name="myBean" class="cn.itsource._07bean.Mybean">
public class Mybean {

    public Mybean(String name,String age){

    }

    public Mybean() {

    }
}

2.方式二 factorybean方式

<bean name="myBeanFactoryBean" class="cn.itsource._07bean.MyBeanFactoryBean"></bean>
//使用FactoryBean创建Bean
public class MyBeanFactoryBean implements FactoryBean<Mybean> {

  //使用getObject()获取bean
  public Mybean getObject() throws Exception {
      return new Mybean("哈哈哈","1");
  }
  //Bean对象类型
  public Class<?> getObjectType() {
      return Mybean.class;
  }
  //单例
  public boolean isSingleton() {
      return false;
  }
}

3.方式三通过静态方法获取bean

<bean class="cn.itsource._07bean.MyBeanFactory" factory-method="getBean"></bean>
public class MyBeanFactory {
  public static Mybean getBean(){
      return  new Mybean();
  }
}

4.使用普通方法创bean

<bean name="myBeanFactory2" class="cn.itsource._07bean.MyBeanFactory2"></bean>
 <bean factory-bean="myBeanFactory2" factory-method="getBean"></bean>
public class MyBeanFactory2 {
 public  Mybean getBean(){
     return  new Mybean();
 }
}

测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext_07.xml")
public class TestBean {

    @Autowired
    private Mybean mybean;
    @Test
    public void testBean()throws Exception{
        System.out.println(mybean);
    }
}

FactoryBean和 BeanFactory 区别?

BeanFactory 他是bean工厂,bean工厂是用IOC容器,得到beanFactory对象(包含所有配置文件的bean), 调用getBean方法 获取对应的工厂里面对象 – 这种方式 使用spring默认获取bean的方式,说白调用无参数的构造方法创建对象FactoryBean:工厂Bean,它的扩展BeanFactory的功能,拿到对象的不是BeanFactory模式。通过调用对应FactoryBean里面getObject获取对应bean

总结出来:beanFactory底层是通过默认无参的构造方法获取对象,FactoryBean 底层是调用getObject方法获取对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值