spring笔记

spring框架的优点
    1,方便解耦,简化开发,可以将所有对象创建和依赖关系维护交给spring管理
    2,Aop编程支持,spring提供面向切面编程,可以方便地实现对程序进行权限拦截,运行监控等功能。
    3,声明式事务的支持,只需通过配置就可以完成对事务的管理,而无须手动编程
    4,方便程序的测试,spring对Junit4支持,可以通过注解方便地测试spring程序
    5,方便集成各种优秀框架,其内部提供了对各种优秀框架的直接支持,struts2,Hibernate,Mybatis等
    6,降低javaEE API的使用难度,对一些难用的javaEE API进行了封装,JDBC,JavaMail,远程调用等
**************************************************************************************************************
spring的Ioc容器
    所谓的Ioc是指在程序设计中,实例不再由调用者来创建,而是由spring容器来创建,spring容器会负责控制程序之间的关系
    而不是由程序代码直接控制,这样控制权由应用代码转移到了外部容器,控制权发生了反转,也就是spring的Ioc(控制反转)的思想
    spring为我们提供了两种Ioc容器,分别为BeanFactory,ApplicationContext

    BeanFactory接口有多种实现,最常见的是使用XmlBeanFactory根据Xml配置文件中的定义来装配Bean
    BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("F:/applicationContext.xml"));
    这种加载方式在实际开发中并不多见,只做了解就好。

    ApplicationContext是BeanFactory的子接口,也被称为应用上下文,创建ApplicationContext接口实例,通常采用两种方法
    ClassPathXmlApplicationContext:从类路径中的Xml文件载入上下文定义信息,把上下文定义文件当作类路径资源,创建语法如下:
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    FileSystemXmlApplicationContext:从文件系统中(指定的路径下)的XML文件载入上下文信息,创建语法如下:
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext
        ("F:\\workspaces\\Spring\\src\\applicationContext.xml");
    两种容器的区别在于,BeanFactory采用了延迟加载方案,只有在调用getBean()时才会实例化Bean,如果Bean的某个属性没有注入,
    使用BeanFactory加载后,在第一次调用getBean()方法时会抛出异常,而ApplicationContext则在初始化时自检,在容器启动后会
    一次性创建所有Bean,这样有利于检查所依赖的属性是否注入。

依赖注入
    依赖注入DI,它与控制反转含义相同,只不过这两个称呼是从两个角度描述同一个概念,依赖注入的作用就是在使用Spring框架创建对象时,
    动态地将其所依赖的对象注入到Bean组件中
    依赖注入存在三种实现方式,分别是setter方法注入,构造方法注入和接口注入,具体介绍如下:
    属性setter注入:指Ioc容器使用setter方法来注入被依赖的实例,通过调用无参构造器或无参static工厂方法实例化Bean后
    调用该Bean的setter方法,即可实现基于setter的DI
    构造方法注入:指Ioc容器使用构造方法来注入被依赖的实例,基于构造器的DI通过调用带参数的构造方法来实现,每个参数代表一个依赖
    接口注入:spring容器不支持接口注入
******************************************************************************************************************
Bean的实例化
    在Spring中,实例化Bean有三种方式,分别为构造器实例化,静态工厂方式实例化和实例工厂方式实例化
    构造器实例化,就是Ioc包下的Demo,什么都没有写,spring容器会自动调用默认的无参构造器对Bean实例化
    静态工厂方式实例化,该方式要求自己创建一个静态工厂的方法来创建Bean的实例
        1,创建一个普通Bean类
        public class StaticBean {
            public void demo()
            {
                System.out.println("测试静态工厂方式实例化。。。。。。。。。。。");
            }
        }
        2,创建一个静态工厂类,并编写静态方法用来返回对象
        public class MyStaticFactory {

            public static StaticBean createBean()
            {
                return new StaticBean();
            }
        }
        3,applicationContext.xml中
        
        4,测试案例
        @Test
        public void staticBeanTest()
        {
            //StaticBean包下测试
            StaticBean staticBean = (StaticBean) applicationContext.getBean("staticBean");
            staticBean.demo();
        }
        静态工厂方式不需要实例化工厂类对象,直接返回Bean对象
    实例工厂方式实例化,该种方式的工厂类中,不再使用静态方法创建Bean实例,而是采用直接创建Bean实例的方式,同时,在配置文件中
    需要实例化的Bean也不是通过class属性直接指向其实例化的类,而是通过factory-bean属性配置一个实例工厂,然后使用factory-method
    属性确定使用工厂中的哪个方法
        1,创建普通的Bean类
        public class ObjectBean {
            public void demo()
            {
                System.out.println("测试动态工厂方式实例化。。。。。。。。。。。。。。。");
            }
        }
        2,创建实例工厂类,并编写工厂方法用来创建Bean
        public class MyObjectFactory {

            public MyObjectFactory() {
                System.out.println("动态工厂类正在实例化。。。。。。。。。。。。");
            }
            public ObjectBean createBean()
            {
                return new ObjectBean();
            }
        }
        3,applicationContext.xml中配置
        
        
        4,测试用例
        @Test
        public void objectBeanTest()
        {
            //ObjectBean包下测试
            ObjectBean objectBean = (ObjectBean) applicationContext.getBean("objectBean");
            objectBean.demo();
        }
    注意:我碰到一个疑问,在配置实例工厂方式实例化时,测试时没错,但当我测试其他例子时,会自动创建MyObjectFactory工厂类实例
    因为我看到在每个测试案例下都运行了实力工厂类的构造器,并运行了其中打印代码”"System.out.println("动态工厂类正在实例化。。。。。。。。。。。。");"
    我不知道为啥,,,,,
****************************************************************************************************************
Bean的作用域
Spring容器在初始化一个Bean实例时,可以同时为其指定特定的作用域,Spring3为Bean实例定义了5种Bean的作用域
    singleton:单例模式,使用singleton定义的Bean在spring容器中将只有一个实例,也就是说,无论多少个Bean引用它,始终将指向同一对象
    这也是spring容器默认的作用域
    prototype:原型模式,每次通过spring容器获取的prototype定义的Bean时,容器都将创建一个新的Bean实例
    request:在一次HTTP请求中,容器会返回该Bean的同一个实例,而对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Request内有效
    session:在一个HTTP Session中,容器会返回该Bean的同一个实例,而对不同的HTTP 请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Session内有效
    global Session:在一个全局的HTTP Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效
    上面5种作用域中,singleton和prototype两种最为常用
*****************************************************************************************************************
Bean的装配方式
Bean的装配可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入的方式,spring容器支持多种形式的Bean的装配方式
基于XML的装配
    spring依赖注入有两种方式:设值注入和构造注入,在spring实例化Bean的过程中,spring首先调用Bean的默认构造方法来实例化Bean对象
    然后通过反射的方式调用setter方法来注入属性值,因此,设值注入要求Bean必须满足以下两点要求:
        Bean类必须提供一个默认的构造方法
        Bean类必须为需要注入的属性提供相应的setter方法
    使用设值注入时,在spring配置文件中,需要使用元素的子元素元素来为每个属性注入值,而使用构造注入时,在配置文件里
    主要使用标签来定义构造方法的参数,可以使用其value属性来设置该参数的值
    applicationContext.xml配置如下
    
        
        
        
    
    
        
        
        
    
基于Annotation的装配
常用的注解如下
    @Component,可以使用此注解描述spring中的Bean,但它只是一个泛化概念
    @Repository,用于将数据访问层(Dao)的类标识为spring中的Bean,功能与@Component相同
    @Service,用于将业务层的类标识为spring中的Bean,功能与@Component相同
    @Controller,通常作用域控制层(struts2的Action),功能与@Component相同
    @Resource,其作用与@AutoWired一样,其区别在于@AutoWired默认按照Bean类型装配,而@Resource默认按照Bean实例名称进行装配,
    其name属性值就是Bean的实例名称
    注解装配需要在applicationContext.xml中配置注解扫描器
        

自动装配
    @AutoWired
    1,作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。
    2,@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
    3,如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?
    可以的,其实异常信息里面也给出了提示了,就是将@Autowired注解的required属性设置为false即可
    代码见AnnotationBean包下的monkey/tiger/zoo案例

    @Qualifier,与@AutoWired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定
    1,当使用注解的属性是接口或抽象类且有多个实现类的时候使用(自己写的,可能不对)
    2,如果容器中有一个以上匹配的Bean,则可以通过@Qualifier注解限定Bean的名称
总结:使用@Component,@Repository,@Service,@Controller注解可以省略掉applicationContext.xml中的bean的注册
使用@Resource,@AutoWired @Qualifier注解可以省略Java代码里面的getter/setter与bean属性中的property。
******************************************************************************************************************
spring的AOP
Aop采取横向抽取机制,取代了传统纵向继承体系重复性代码,主要体现在事务处理,日志管理,权限控制,异常处理等方面,使开发人员在编写
业务逻辑时可以专心于核心业务,提高了代码的可维护性,目前最流行的AOP框架有两个Spring AOP和AspectJ。
AOP术语
    JoinPoint(连接点):简单的说就是目标类中的方法
    Pointcut(切入点):简单的说就是被增强的连接点
    Advice(通知):简单的说就是在切入点前后执行的方法,也是切面类中的方法
    Target(目标):就是将要被增强的类,连接点就在里面
    Weaving(织入):就是把通知添加到切入点前后,生成代理对象的过程
    Proxy(代理):就是目标类+通知生成的代理类,也就是增强后的目标类
    Aspect(切面):包含了要增强的方法,将通知包装成一个类
手动代理
    AOP手动代理有两种代理模式分别为JDK动态代理和CGLIB代理
    JDK动态代理:目标类必须实现接口
    CGLIB代理:如果目标类没有实现接口的类就可使用CGLIB代理
    注:手动代理太复杂,不想敲了
声明式工厂Bean
Spring通知类型
    通知就是对目标切入点增强的内容,spring通知按照在目标类方法的连接点位置分为5种类型
    MethodBeforeAdvice,前置通知,可以应用于权限管理等功能
    MethodReturningAdvice,后置通知,可以应用于关闭流,上传文件,删除临时文件等功能
    MethodInterceptor,环绕通知,可以应用于日志,事务管理等功能
    ThrowsAdvice,异常抛出通知,可以应用于处理异常记录日志等功能
    IntroductionInterceptor,引介通知,可以应用于修改老版本程序(增强类)
声明式Spring AOP框架,在运行时期通过代理的方式向目标类织入增强的代码
    UserDao接口
        public interface UserDao {
            public void add();
            public void delete();
            public void update();
            public void query();
        }
    UserDaoImpl实现类
        @Repository
        public class UserDaoImpl implements UserDao {
            @Override
            public void add() {
                System.out.println("增加用户。。。。。。。。。。。");
            }

            @Override
            public void delete() {
                System.out.println("删除用户。。。。。。。。。。。");
            }

            @Override
            public void update() {
                System.out.println("修改用户。。。。。。。。。。。");
            }

            @Override
            public void query() {
                System.out.println("查询用户。。。。。。。。。。。。");
            }
        }
    切面类MyAspect
        @Component
        public class MyAspect implements MethodInterceptor {

            //需要确定实现哪个通知接口,及告诉spring应该执行哪个方法
            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                System.out.println("方法执行之前");
                Object obj = methodInvocation.proceed();
                System.out.println("方法执行之后");
                return obj;
            }
        }
    applicationContext中的配置
        
        
            
            
            
            
            
            
            
            
        
    测试实例
        @Test
        public void StatementAopTest() {
            //StatementAop包下测试,AOP框架中的SpringAOP
            UserDao proxy =
            (UserDao) applicationContext.getBean("userDaoProxy");
            proxy.add();
            proxy.delete();
            proxy.update();
            proxy.query();
        }
*****************************************************************************************************************
AspectJ开发AOP
基于XML的声明式AspectJ
    基于XML声明式AspectJ是指,通过在XML文件中进行配置,来定义切面,切入点及声明通知,所有的切面和通知都必须定义在元素中
    applicationContext.xml内容如下
    
        
            
            
            
            
            
            
            
            
            
        
    
    切面类如下
    @Component
    public class MyAspectJ {

        //前置通知
        public void myBefore(JoinPoint joinPoint)
        {
            System.out.println("前置通知,目标:");
            System.out.println(joinPoint.getTarget()+",方法名称:");
            System.out.println(joinPoint.getSignature().getName());
        }

        //后置通知
        public void myAfter(JoinPoint joinPoint)
        {
            System.out.println("后置通知,方法名称:"+joinPoint.getSignature().getName());
        }

        /*
        * 环绕通知
        * ProceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
        * 1,必须返回Object类型值
        * 2,必须接收一个参数,类型为ProceedingJoinPoint
        * 3,必须throws Throwable
        */
        public Object myAround(ProceedingJoinPoint point) throws Throwable {
            System.out.println("电音环绕开始");
            Object obj = point.proceed();
            System.out.println("电音环绕结束");
            return obj;
        }

        //异常通知
        public void myException(JoinPoint joinPoint,Throwable e)
        {
            System.out.println("异常通知,出错了:"+e.getMessage());
        }

        //最终通知
        public void myEnd()
        {
            System.out.println("最终通知");
        }

    }
    测试用例如下
    @Test
    public void StatementAspectJTest() {
        //StatementAop包下测试,AOP框架中的AspectJ
        UserAopDao proxy = (UserAopDao) applicationContext.getBean("userAopDaoImpl");
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.query();
    }
基于Annotation的声明式AspectJ
    只需要在切面类中使用注解即可,无需在配置文件中增加AOP的代码
    切面类
    @Aspect
    @Component
    public class MyAspectJ2 {

        @Pointcut("execution(* top.kubino1.StatementAop.UserAopDaoImpl.*(..))")
        private void myPointCut(){}

        //前置通知
        @Before("myPointCut()")
        public void myBefore(JoinPoint joinPoint)
        {
            System.out.println("前置通知,目标:");
            System.out.println(joinPoint.getTarget()+",方法名称:");
            System.out.println(joinPoint.getSignature().getName());
        }

        //后置通知
        @AfterReturning("myPointCut()")
        public void myAfter(JoinPoint joinPoint)
        {
            System.out.println("后置通知,方法名称:"+joinPoint.getSignature().getName());
        }

        /*
        * 环绕通知
        * ProceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
        * 1,必须返回Object类型值
        * 2,必须接收一个参数,类型为ProceedingJoinPoint
        * 3,必须throws Throwable
        */
        @Around("myPointCut()")
        public Object myAround(ProceedingJoinPoint point) throws Throwable {
            System.out.println("电音环绕开始");
            Object obj = point.proceed();
            System.out.println("电音环绕结束");
            return obj;
        }

        //异常通知
        @AfterThrowing(value = "myPointCut()",throwing = "e")
        public void myException(JoinPoint joinPoint,Throwable e)
        {
            System.out.println("异常通知,出错了:"+e.getMessage());
        }

        //最终通知
        @After("myPointCut()")
        public void myEnd()
        {
            System.out.println("最终通知");
        }

    }
    配置文件中需要开启自动代理
    
    
    测试用例
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class AspectJTest {
        @Resource(name = "userAopDaoImpl")
        private UserAopDao userAopDao;

        @Test
        public void demo()
        {
            userAopDao.add();
        }
    }
*******************************************************************************************************************
Spring事务管理
    spring的事务管理是基于AOP实现的,而AOP是以方法为单位的,spring的事务属性分别为传播行为,隔离级别,只读和超时属性,所有这些属性提供了
    事务应用的方法和描述策略,spring的事务处理位于业务逻辑层并提供了针对性的解决方案
spring事务管理的三个核心接口
    1,PlatformTransactionManager接口是spring提供的平台事务管理器,用于管理事务,该接口中提供了三个事务操作方法,具体如下
        TransactionStatus  getTransaction(TransactionDefinition definition),用于获取事务状态信息
        void commit(TransactionStatus status),用于提交事务
        void rollback(TransactionStatus status),用于回滚事务
    2,TransactionDefinition接口是事务定义(描述)对象,提供事务相关信息的获取方法,包含5个操作,具体如下
        String getName(),获取事务对象名称
        int getIsolationLevel(),获取事务的隔离级别
        int getPropagationBehavior(),获取事务传播行为
        int getTimeout(),获取事务超时时间
        boolean isReadOnly(),获取事务是否只读
    3,TransactionStatus接口是事务的状态,描述了某一时间点上事务的状态信息,包含6个操作,具体如下
        void flush(),刷新事务
        boolean hasSavepoint(),获取是否存在保存点
        boolean isCompleted(),获取事务是否完成
        boolean isNewTransaction(),获取是否是新事务
        boolean isRollbackOnly(),获取是否回滚
        void setRollbackOnly(),设置事务回滚
spring的事务管理分为两种方式,分别为声明式事务管理和编程式事务管理
    编程式事务管理使用事务管理模板TransactionTemplate手动地管理事务,在实际开发中一般不使用
    声明式事务管理可以分为两种或者说三种
        基于springAOP的声明式事务管理
            
            
                    
                    
                    
                    
                    
                    
                    
                    
                            
                                    PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ
                            
                    
            
        基于AspectJ-XML方式的声明式事务管理
            
            
            
                
                    
                
            
            
            
                
                
                
                
            
        基于AspectJ注解形式的声明式事务管理
            
            
            
            
*****************************************************************************************************************
SSH整合
    前端Jsp页面表单提交数据到struts.xml中,并调用相应的Action
    struts.xml
        
            
            

            
                
                    /success.jsp
                    /index.jsp
                    ssh_login.action
                    login,update
                
            
        
    Action页面
        @Controller
        public class StudentAction extends ActionSupport implements ModelDriven {

            @Resource(name = "studentinfo")
            private Studentinfo student;

            @Resource(name = "teacherinfo")
            private Teacherinfo teacher;

            public Teacherinfo getTeacher() {
                return teacher;
            }

            @Override
            public Studentinfo getModel() {
                return student;
            }

            @Resource(name = "studentServiceImpl")
            private StudentService studentService;

            public StudentService getStudentService() {
                return studentService;
            }

            public void queryAll() {
                List list = this.studentService.queryAll();
                ActionContext.getContext().put("list",list);
            }

            public String login() {
                if ("teacher1".equals(teacher.getTeacherName()) && "123765".equals(teacher.getTeacherPassword())) {
                    queryAll();
                    return "success";
                } else {
                    return "index";
                }
            }


            public String update() {
                this.studentService.updateStudent(student);
                return "update";
            }
        }
    在Action中调用服务层StudentServiceImpl类的方法,服务层中调用持久层的方法,
    持久层使用HibernateTemplate将Bean中的数据保存到数据库中
    StudentServiceImpl中
        @Service
        public class StudentServiceImpl implements StudentService {

            @Resource(name = "studentDaoImpl")
            private StudentDao studentDao;

            @Transactional
            @Override
            public void addStudent(Studentinfo student) {
                studentDao.add(student);
            }

            @Transactional
            @Override
            public void deleteStudent(Studentinfo student) {
                studentDao.delete(student);
            }

            @Transactional
            @Override
            public void updateStudent(Studentinfo student) {
                studentDao.update(student);
            }

            @Transactional
            @Override
            public Studentinfo queryStudentById(Integer id) {
                return studentDao.queryById(id);
            }

            @Transactional
            @Override
            public List queryAll() {
                return studentDao.queryAll();
            }
        }
     StudentDaoImpl中
        @Repository
        public class StudentDaoImpl  implements StudentDao {

            @Resource(name = "hibernateTemplate")
            private HibernateTemplate hibernateTemplate;

            @Override
            public void update(Studentinfo student) {

                this.hibernateTemplate.update(student);
            }

            @Override
            public void add(Studentinfo student) {
                this.hibernateTemplate.save(student);
            }

            @Override
            public void delete(Studentinfo student) {
                this.hibernateTemplate.delete(student);
            }

            @Override
            public Studentinfo queryById(Integer id) {
                return this.hibernateTemplate.get(Studentinfo.class, id);
            }

            @Override
            public List queryAll() {
                List list = (List) this.hibernateTemplate.find("from Studentinfo");
                return list;
            }
        }
    ApplicationContext.xml页面
        
            

            
            

            
            
                
                
                
                
            

            
            
                
                
                
                
                    
                        org.hibernate.dialect.MySQL5Dialect
                        true
                        jdbc:mysql://localhost:3306/sshintegration
                        com.mysql.jdbc.Driver
                        
                        
                        
                    
                
                
                
                    
                        top.kubino1.Web.Bean.Studentinfo
                        top.kubino1.Web.Bean.Teacherinfo
                    
                
            

            
                
            

            
            
                
            

            
            

        
    HibernateTemplate,相当于Hibernate的Session
    HibernateTransactionManager,相当于Hibernate的事务管理器
    c3p0.properties页面中
        jdbc.driverClass=com.mysql.jdbc.Driver
        jdbc.jdbcUrl=jdbc:mysql://localhost:3306/sshintegration
        jdbc.user=root
        jdbc.password=123765
在整个SSH整合过程中,使用了Hibernate的注解和spring的事务注解,并且选择不使用Hibernate.cfg.xml文件,
直接将SessionFactory定义在applicationContext.xml中。
*******************************************************************************************************************


你可能感兴趣的:(spring)