Spring

Spring的两个核心概念

  • IOC      (Inversion of Control 控制反转)
  • AOP     (Aspect Orient Programming 面向切面编程)

 

 IOC 方面用Annotation要比用XML更方便

 AOP方面用XML要比用Annotation更强大

IOC

控制反转和依赖注入

     

       控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。

有一个实体操作接口和实现类

public interface UserDAO {
    public void save(User user);
}



public class UserDAOImpl implements UserDAO {

    public void save(User user) {        
        System.out.println("user saved!");
    }
}

有一个实体类

public class User {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
User

有一个工具类

public class UserService {
    private UserDAO userDAO;  
    public void add(User user) {
        userDAO.save(user);
    }
    public UserDAO getUserDAO() {
        return userDAO;
    }
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
}

 由一个测试类

public class UserServiceTest {

    @Test
    public void testAdd() throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");        
        
        UserService service = (UserService)ctx.getBean("userService");        
        
        User u = new User();
        u.setUsername("zhangsan");
        u.setPassword("zhangsan");
        service.add(u);
    }
}

     注意这里红线的部分,有参数,说明可以指定xml的位置,同时他还有一个方法是xml数组,就是可以传多个xml进去 

     多个配置文件的好处就是团队协作,不同的人写不同的配置文件,不会冲突

      

      从测试类本身来看,需要两个地方进行初始化

      service对象的初始化,以及add方法中使用的是UserDAO 的哪一个实现类是没有指定的(也就是内部的UserDao没有初始化)。

      但是加入了一个容器:

         XML方式的注入

<beans >

  <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">
  </bean>    
  <bean id="userService" class="com.bjsxt.service.UserService">
      <property name="userDAO" ref="u" />          
  </bean> 
</beans>
  • bean相当于new一个对象
  • ref相当于引入一个已经new的对象 

          之后,在spring框架下,这个程序是可以正常运行的。

          也就是说把具体对象的初始化交给这个容器来完成。这个就是控制反转的意义

          控制反转意思就是说以前可以在类中控制具体的初始化,现在交给由容器完成

          具体的类 从控制实现到控制抽象(接口),从实现具体的东西,到实现抽象的东西

          也就是说UserService 类里面不需要初始化DAO对象

          UserServiceTest 类里面也不需要初始化UserService对象

           这些都交给容器来完成

          service.add(u)    具体add的具体实现依赖于容器注入给的DAO对象,这个就是依赖注入

1.注入类型

主要有两种

  • setter注入
  • 构造方法注入

        setter注入就是使用set方法

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...

}

       bean.xml不变

       构造方法注入用的很少

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

2.name和id

  <bean name="u" class="com.bjsxt.dao.impl.UserDAOImpl">
  </bean>

        这两个基本一致,没啥区别

3.简单属性的注入

  对类中一般属性进行注入,很少用

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

4.集合注入

5.bean的生存范围

 <bean name="u" class="com.bjsxt.dao.impl.UserDAOImpl"  scope="XX">
  </bean>

默认是singleton,单例

  结果是true

  

   如果类是struct的Action,范围是prototype

6.bean生命周期

  • Lazy-initialized beans

不加的话在用到xml

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

这句话的时候就初始化所有的bean

加上的话就是在使用getBean方法的时候初始化

相当的用的少

只有当程序启动很慢的时候,才用到

  • init-method destroy-methd
public class UserService {
    
    private UserDAO userDAO;  
    
    public void init() {
        System.out.println("init");
    }
    
    public void add(User user) {
        userDAO.save(user);
    }
    public UserDAO getUserDAO() {
        return userDAO;
    }
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
    
    public UserService(UserDAO userDAO) {
        super();
        this.userDAO = userDAO;
    }
    
    public void destroy() {
        System.out.println("destroy");
    }
}
    
  <bean id="userService" class="com.bjsxt.service.UserService" init-method="init" destroy-method="destroy" scope="prototype">

       <constructor-arg>
           <ref bean="u"/>
       </constructor-arg>
  </bean>

init-method destroy-methd 不要和prototype一起用

也是很少用,比如数据源连接池的时候用destroy,关闭连接池

7.自动装配 Autowire

  <bean name="userDAO" class="com.bjsxt.dao.impl.UserDAOImpl">
      <property name="daoId" value="1"></property>
  </bean>
  
  <bean name="userDAO2" class="com.bjsxt.dao.impl.UserDAOImpl">
      <property name="daoId" value="2"></property>
  </bean>
    
  <bean id="userService" class="com.bjsxt.service.UserService" scope="prototype" autowire="byName">
  </bean>

   byName自动装配/

   最后一个bean没有指定,但是他所在的类里的属性是userDAO,它就根据这个name找到了第一个bean

      前面都是xml形式的,下面说一下

Annotation的IOC

    Annotation的注入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
  <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">
  </bean>    
  <bean id="userService" class="com.bjsxt.service.UserService">
        
  </bean> 
</beans>

</beans>

   

   

     使用AutoWire加入注入

     autowire会自动到配置文件中去找一个与参数对应类型的bean,注入进来

     AutoWire可以加在任意方法上,只有这个方法需要注入

public class UserService {
    private UserDAO userDAO;  
    public void add(User user) {
        userDAO.save(user);
    }
   
   
    @Autowire
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
}
public class UserServiceTest {

    @Test
    public void testAdd() throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");        
        
        UserService service = (UserService)ctx.getBean("userService");        

        service.add(new User());
    }
}

     可以看出它注入的方式是byType

但是如果

 <bean id="u1" class="com.bjsxt.dao.impl.UserDAOImpl">
  </bean>    
 <bean id="u2" class="com.bjsxt.dao.impl.UserDAOImpl">
  </bean>   
  <bean id="userService" class="com.bjsxt.service.UserService">
        
  </bean> 

这时候就需要Qualifier

public class UserService {
    private UserDAO userDAO;  
    public void add(User user) {
        userDAO.save(user);
    }
   
   
    @Autowire
    public void setUserDAO(@Qualifier("u1")  UserDAO userDAO) {
        this.userDAO = userDAO;
    }
}

    autowire用的不多,下面这种用的比较多

     

Resouce

     它默认的注入方式也是byName,如果name找不到,就byType

      想指定名字,直接写

     @Resource(name="u")

   @Resource
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

     

 以上所有的方式在配置文件里面都要写待注入的bean

使用

     Component 

     只需要一句,其他的都不用写了

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="org.example"/>
    
    org.example表示扫描这个包下面的所有类,发现写有Component的类,然后把他放在容器里面,形成一个bean。name就是类名首字母小写,如果想指定名字,就在类上加上@componet("newname"),value就是对象。推荐写名字      
  </bean> 
</beans>
    @Test
    public void testAdd() throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");        
        
        UserService service = (UserService)ctx.getBean("userService");        

        service.add(new User());
    }

那么它是怎么注入的呢

在注入类上加入

@Component
public class UserDAOImpl implements UserDAO {

    public void save(User user) {        
        System.out.println("user saved!");
    }
}

       

       componet 相当于是一个组件,就是把这个类产生的对象当成一个组件,这个组件对于另外一个类来说就是一个资源

public class UserService {
    private UserDAO userDAO;  
    public void add(User user) {
        userDAO.save(user);
    }   
   
    @Resouce
    public void setUserDAO( UserDAO userDAO) {
        this.userDAO = userDAO;
    }
}

       默认得,spring中 @Component@Repository@Service@Controller, 这四个注解用法一样,都可以把类当初一个组件资源

      注解里面还有有Scope,postConstruct,PreDestroy(相当于xml中的init和destory)

AOP

          是对面向对象的思维方式的有力补充

         和面向对象并不矛盾,简单来说一个是横着编程,一个是竖着编程

         也是两种实现配置方式

  •           Annotation
  •           XML

        Annotation方式:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <context:annotation-config />
    <context:component-scan base-package="com.bjsxt"/>
     <aop:aspectj-autoproxy />

</beans>

         <aop:aspectj-autoproxy />  的意思是自动产生代理

     Aspectj是一个专门产生动态代理,专门面向AOP编程的框架,sprig使用了它

         切入点语法: 

@Aspect
@Component
public class LogInterceptor {

    @Before("execution(public void com.bjsxt.service.UserDAO.add(com.bjsxt.User))") 
public void myMethod(){};

}

           @Component初始化这个类 

           @Aspect表示这个是个切面逻辑

    @Pointcut("execution(public * com.bjsxt.service..*.add(..))")
    public void myMethod(){};
    }

         pointcut连接点集合

          要加入切面的类必须要由spring管理起来,就是在bean.xml中能找到这个类,也可以说在类上加@Component

      XML方式

        这种方式更重要

        加入使用别人的切面类,不可能往人家源码上加Annotation

       切面类

public class LogInterceptor {
    public void myMethod(){};
    
    public void before() {
        System.out.println("method before");
    }
    
    public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("method around start");
        pjp.proceed();
        System.out.println("method around end");
    }
    
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      .......>


<context:annotation-config /> <context:component-scan base-package="com.bjsxt"/> <bean id="logInterceptor" class="com.bjsxt.aop.LogInterceptor"></bean> <aop:config> <aop:aspect id="logAspect" ref="logInterceptor"> <aop:before method="before" pointcut="execution(public * com.bjsxt.service..*.add(..))" /> </aop:aspect> </aop:config> </beans>
原文地址:https://www.cnblogs.com/tech-bird/p/4167601.html