• 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>
  • 相关阅读:
    杭电2059
    杭电2058
    php错误大集合
    显示IP地址
    超简单好用的屏幕录像工具
    jquery“不再提醒"功能
    KindEditor编辑器中的class自动过滤了
    实用案例:切换面板同时切换内容
    仿51返利用户图解教程
    JavaScript调用dataTable并获取其值(ASP.Net,VS2005)
  • 原文地址:https://www.cnblogs.com/tech-bird/p/4167601.html
Copyright © 2020-2023  润新知