JavaWeb框架-【Spring】-2-让你我痴迷滴Spring!

本文深入探讨Spring框架的核心特性,包括构造方法注入、自动装配、注解使用、设计模式的应用、自定义注解以及AOP的多种实现方式。通过具体示例帮助读者掌握Spring的基本原理和技术要点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

话说:

各位读者早上好,上一篇博客初步了解了下Spring,这篇深入总结下。
Hibernate、Struts2现在主流用得少了,但是它们蕴含的思想还是蛮好的;Spring则非常强大,如春天般生机盎然。主流的SSM开发框架中的springMVC及MyBatis将在后续几篇博客中“粉墨登场”。到现在为止SSH的每个成员就介绍完毕了,下一篇博客将整合Spring+Struts2+Hibernate。

还是那句话,技术会过时,但是其中孕育的思想不会过时。

开发环境
IntelliJ IDEA(2017.2.5)

目录:


一、构造方法注入
二、自动装配
三、注解
四、设计模式
五、三种方式实现AOP
六、总结


一、构造方法注入

整体布局如下:

这里写图片描述

这次引入接口,通过面向接口编程的方式,来实现构造方法注入。类中以接口作为属性,然后配置bean,接着配置bean的属性。属性如果不注入,就会报错:NullPointExcepiton

前期准备:
新建IUserDao、UserDao负责数据持久化;IUserService、UserService业务逻辑处理。

IUserDao

package com.hmc.spring.dao;

public interface IUserDao {
    void add();
}

UserDao

package com.hmc.spring.dao;

/**
 * User:Meice
 * 2017/11/4
 */
public class UserJdbcDao implements  IUserDao {
    public void add() {
        System.out.println("使用JDBC方式保存用户....");
    }
}

IUserService

package com.hmc.spring.service;

public interface IUserService {
    void save();
}

UserService

package com.hmc.spring.service;
import com.hmc.spring.dao.IUserDao;

/**
 * User:Meice
 * 2017/11/4
 */
public class UserService implements IUserService {
 //   private IUserDao userJdbcDao;
    private IUserDao userDao;



    /*public IUserDao getUserJdbcDao() {
        return userJdbcDao;
    }

    public void setUserJdbcDao(IUserDao userJdbcDao) {
        this.userJdbcDao = userJdbcDao;
    }*/



    //最好一同也写一个无参的,避免忘记带参构造方法属性注入时报错:No default constructor found;
    public UserService() {}

    //构造方法初始化
    public UserService(IUserDao userDao) {
        this.userDao = userDao;
    }



    public void save() {
        //这里面要调用JDBC的add方法
        userDao.add();

        //自动装配autowire="byName"
        //userJdbcDao.add();
    }



   /* public IUserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(IUserDao userDao) {
        this.userDao = userDao;
    }
    */

}

我们的目的是在UserService里面要调用IUserDao中的方法,本质就是调用UserJdbcDao中的方法。不过这里属性我们定义为接口,而不是直接是对应Dao层类。什么用呢?方便扩展。下次再增加IBookDao、BookDao就很方便。

上一篇博客我们是怎么注入的?我们定义了属性IUserDao,然后生成get(),set()方法,在spring.xml中配置UserService的bean,然后给这个bean配置property,属性名字要和set()后的setYY 中的yy保持一致。

这里要实现的目标是,通过构造方法属性注入,就不用生成set()了。如何实现构造方法注入?

第一步:UserService中生成构造方法

package com.hmc.spring.service;
import com.hmc.spring.dao.IUserDao;

/**
 * User:Meice
 * 2017/11/4
 */
public class UserService implements IUserService {
    private IUserDao userDao;
    //最好一同也写一个无参的,避免忘记带参构造方法属性注入时报错:No default constructor found;
    public UserService() {}

    //构造方法初始化
    public UserService(IUserDao userDao) {
        this.userDao = userDao;
    }



    public void save() {
        //这里面要调用JDBC的add方法
        userDao.add();

        //自动装配autowire="byName"
        //userJdbcDao.add();
    }


}

第二步:spring.xml中配置

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

    <!--注入userJdbcDao-->
    <bean name="userJdbcDao" class="sdcom.hmc.spring.dao.UserJdbcDao"></bean>
  <!--  <bean name="userHibernateDao" class="com.hmc.spring.dao.UserHibernateDao"></bean>-->
    <!--注入userService-->
    <bean name="userService" class="com.hmc.spring.service.UserService" autowire="constructor">
        <!--byName表示根据bean的名字来自动装配,所以引用的时候,属性名要和bean名字一致并生成get(),set()
        而且,给哪个bean加上自动装配,表示对其引用属性进行自动装配,而不是其本身-->
        <!--属性注入-->
        <!--<property name="userDao" ref="userJdbcDao"></property>-->

        <!--构造方法注入-->
         <constructor-arg index="0" ref="userJdbcDao"></constructor-arg>

    </bean>

</beans>

无非就是换一种方式注入属性而已。需要注意的是,这里如果没有配置,就会报错:NullPointException,因为找不到具体属性值呢。

二、自动装配

自动装配就是通过一个属性Autowired来配置属性,替换之前需要配置
property这个属性节点。

主要类型:no、 byName、byType、constructor

1) byName
顾名思义,byName,属性名不可以乱取;定义属性名字要和要引用的bean一致。
第一步:定义属性并生成get() set()

 private IUserDao userJdbcDao;

             public IUserDao getUserJdbcDao() {
                return userJdbcDao;
            }

            public void setUserJdbcDao(IUserDao userJdbcDao) {
                this.userJdbcDao = userJdbcDao;
            }

第二步:自动装配 加上autowire=”byName”

 <bean name="userJdbcDao" class="com.hmc.spring.dao.UserJdbcDao"></bean>
             <bean name="userService" class="com.hmc.spring.service.UserService" autowire="byType">
                        //这里神马也不用写奥~~~
            </bean>

注意:这里因为是byName,定义的属性userJdbcDao要和bean的name一致,否则就报错NullPointExcep,找不到嘛!

2) byType

顾名思义,根据类型。什么类型,你定义的属性,要注入的属性的类型。所以名字随便取。

第一步:定义接口属性,并生成get set

private IUserDao userDao;

            public IUserDao getUserDao() {
                return userDao;
            }   

            public void setUserDao(IUserDao userDao) {
                this.userDao = userDao;
            }

第二步:自动装配 加入:autowire=”byType”

 <bean name="userJdbcDao" class="com.hmc.spring.dao.UserJdbcDao"></bean>
             <bean name="userService" class="com.hmc.spring.service.UserService" autowire="byType">
                //这里神马也不用写
             </bean>

But!

弊端:如果这个接口有多个类实现,就会找不到具体调用哪个类的方法了。会报错:

java.lang.ExceptionInInitializerError
            Caused by: ....NoUniqueBeanDefinitionException: No qualifying bean of type 'com.hmc.spring.dao.IUserDao' available: expected single matching bean but found 2: userJdbcDao,userHibernateDao

所以,谨慎使用。用的时候,属性就不要定义为接口了,直接定义为对应的实现类。

3) constructor

构造方法,顾名思义,之前的构造方法属性注入也可以通过autowire=”constructor”来配置
第一步:定义接口类型属性和构造方法

private IUserDao userDao;
             public UserService() {}

            //构造方法初始化
            public UserService(IUserDao userDao) {
                this.userDao = userDao;
            }

第二步:加入自动装配constructor

第二步:加入自动装配constructor
            <bean name="userJdbcDao" class="com.hmc.spring.dao.UserJdbcDao"></bean>

            <!--注入userService-->
            <bean name="userService" class="com.hmc.spring.service.UserService" autowire="constructor">
                //这里神马也不用写!
            </bean>

But!
和byType一样,如果有多个类实现同一个接口,那么系统就不知道该调用实现类的方法
就会报错:java.lang.NullPointerException;比如以下两个bean都实现了IUserDao这个接口的add()方法

<bean name="userJdbcDao" class="com.hmc.spring.dao.UserJdbcDao"></bean>
            <bean name="userHibernateDao" class="com.hmc.spring.dao.UserHibernateDao"></bean>
            <!--注入userService-->
            <bean name="userService" class="com.hmc.spring.service.UserService" autowire="constructor">

</bean>

三、注解

什么用呢?之前我们每次都要在spring.xml中配置bean,就代表类实例化了,这样有木有觉得很麻烦?是的,确实如此。怎么简化呢?注解。注解大家很熟悉,Junit中的@Test从此解放了main方法,测试起来灰常方便了呢。

1)主要几个注解@Repository @Service @Controller @Autowired @Qualifier 等

如何实现注解呢?

(1)开启注解支持
官方文档在spring.xml中加入头部信息

   xmlns:context="http://www.springframework.org/schema/context"

    http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd

(2) 扫描加入注解的包

<context:component-scan base-package="com.hmc.spring"/>

(3)给相应业务类加上相应注解

Dao层
            @Repository
            public class UserDao implements IUserDao {}

        Service层
            @Service
            public class UserService implements  IUserService {}

        Autowired实现自动装配
            @Autowired(默认byType)
            private IUserDao userDao;
            可以使用Qualfier指定bean的名称

             @Autowired
            @Qualifier(value = "userJdbcDao")——手动指定在哪个bean进行装配
            private IUserDao userDao;

如果生成了get() set()方法,就通过@Resource方法注解,等同于@Autowired + @Qualifier

    private IUserDao userDao;

             public IUserDao getUserDao() {
                return userDao;
            }

            @Resource(name = "userHibernateDao")//生成set()方法,通过Resource( name=""指定属性)
            public void setUserDao(IUserDao userDao) {
                this.userDao = userDao;
            }

注意:@Service 和@Repository默认就是类名首字母小写,如果重命名的话,引用的时候,也要用引用的名字,否则报错:
No bean named ‘userJdbcDao’ available

2)自定义注解

我们不能总做使用者吧?如果可能,我们也要尽可能去创造。

1、新建一个注解类

package com.hmc.spring.annotation;
        import java.lang.annotation.ElementType;
        import java.lang.annotation.Retention;
        import java.lang.annotation.RetentionPolicy;
        import java.lang.annotation.Target;


@Target({ElementType.METHOD})  //表示在元素上运行
@Retention(RetentionPolicy.RUNTIME) //注解在运行时有效
public @interface Log_meice {

    String value() default "";
}

2、加入元注解

@Target({ElementType.METHOD})  //表示在元素上运行
@Retention(RetentionPolicy.RUNTIME) //注解在运行时有效

3、测试

package com.hmc.spring.dao;
import com.hmc.spring.annotation.Log_meice;
public interface IUserDao {
    @Log_meice("增加了用户")
    void add();

    @Log_meice("更新了用户")
    void update();

    @Log_meice("删除了用户")
    void del();

    void list();
}

四、设计模式

就是把所有的代码结构化分层,每一层职责明确。不论项目多么复杂,项目结构清晰明了。Model层
就是JavaBean,业务类的实体类;Dao层负责数据持久化,和数据库接入;Service层调用Dao层方法,实现
复杂的业务逻辑处理,Controller层主要做三件事:处理页面请求并接收参数、调用Service层方法、页面跳转。
各层层级关系明朗:Controller==>Service==>Dao 上层依赖于下层,下层为上层提供服务。

其实《金字塔结构》这本书讲解的是平时说话做事的逻辑层级;在代码世界里,本质也差不多。

五、三种方式实现AOP

1)经典方式:静态代理与动态代理
2)注解方式
3)XML配置方式

AOP——Aspect-Oriented Programming 面向切面编程
OC原则(open close);在不改编源码的情况下,为原代码织入新功能。
底层依赖的JDK的反射机制。反射我们不陌生了,之前JDBC一些列中,查的方法最后用到了Field.

1)经典方式:静态代理与动态代理

a、静态代理如何实现?
b、动态代理?

目的:UserService在调用Dao层add()方法时,为其增加日志信息。日志信息内容如下:

package com.hmc.spring.log;

import java.util.Date;

/**
 * User:Meice
 * 2017/11/5
 */
public class Logger {
    public static void log(String info) {
        System.out.println(new Date()+"--->"+info);
    }

}

a、静态代理如何实现?

package com.hmc.spring.dao;
import com.hmc.spring.log.Logger;
import org.springframework.stereotype.Repository;

/**
 * User:Meice
 * 2017/11/5
 */
@Repository
public class UserProxyJdbcDao implements IUserDao {
    /**
     * 静态代理步骤:
     * 1、创建一个和要添加功能一模一样的Dao
     * 2、加入新增方法
     * 3、注解(自动装配)
     */
    public void add() {
        System.out.println("使用JDBC新增了用户....");
        Logger.log("添加了用户");
    }

    public void update() {

    }

    public void del() {

    }

    public void list() {

    }
}

b、动态代理?

先单纯实现动态代理,不与spring整合。

package com.hmc.spring.proxy;
import com.hmc.spring.dao.IUserDao;
import com.hmc.spring.dao.UserJdbcDao;
import com.hmc.spring.log.Logger;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * User:Meice
 * 2017/11/5
 */
public class LoggerProxy implements InvocationHandler {
    //代理对象-->代言人
    private Object target;

    public LoggerProxy(Object o) {//被代理对象->产品
        this.target = o;
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("嗯哈");
       // Logger.log("Before:进行了相关操作");
      Object obj =  method.invoke(target,args);
       // Logger.log("After:进行了相关操作");
        return obj;
    }




    public static void main(String[] args) {
        UserJdbcDao userJdbcDao = new UserJdbcDao();//被代理对象
        LoggerProxy proxy =   new LoggerProxy(userJdbcDao); //得到代理对象

    /* IUserDao userDaoProxy =(IUserDao)Proxy.newProxyInstance(UserJdbcDao.class.getClassLoader(),IUserDao.class.getInterfaces(),proxy);
     userDaoProxy.add();*/
        /**
         * 运行结果:
         * java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.hmc.spring.dao.IUserDao
         */


        IUserDao ud =(IUserDao)Proxy.newProxyInstance(UserJdbcDao.class.getClassLoader(),UserJdbcDao.class.getInterfaces(),proxy);
            ud.add();

        /**
         * 以上整体执行流程是这样的:
         * ud.add(),ud表示指定的接口(IUserDao)的代理实例,,该接口将add()方法的调用指派到指定的调用处理程序-proxy
         * 调用处理程序就是指实现InvocationHandler接口的这个类,也就是这里的LoggerProxy,只要把它实例化——通过带参构造
         * 方法把被代理对象-UserJdbcDao传过去即可。
         *
         * 最终,你看到的输出信息,就是这个类中invoke()方法体重输出的信息,而不是原有UserJdbcDao中的方法。
         * 因为方法已经通过Method的invoke方法从底层映射过来了。
         *
         * 再说简单点:也就是通过2步走就把UserJdbcDao中的add()方法复制了一份到这个调用处理程序中。然后在这里
         * 加入我们需要增加的内容,而不改变原有方法。
         *
         * 第一步:创建一个类,实现InvocationHandler接口,并实现方法。(这个类就是调用处理程序)
         * 第二步:通过Proxy这个类实例化该调用处理程序,实例化过程中就制定了代理产品-UserJdbcDao
         *
         *
         */




    }


}

通过spring.xml来实现动态代理
首先编写一个类,类似上面的。

package com.hmc.spring.proxy;
import com.hmc.spring.annotation.Log_meice;
import com.hmc.spring.dao.IUserDao;
import com.hmc.spring.log.Logger;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * User:Meice
 * 2017/11/5
 */
public class LoggerProxySpring  implements InvocationHandler{
    //制定代理人
    private  Object target;

   /* public LoggerProxySpring(Object o) {
        this.target = o;
        Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this);
    }*/

    /**
     *  构造方法无法返回Proxy实例化后被代理对象实现的接口
     就会报错: No qualifying bean of type 'com.hmc.spring.dao.IUserDao' available: expected at least 1 bean which
     qualifies as autowire candidate. Dependency annotations:
     {@org.springframework.beans.factory.annotation.Autowired
     (required=true), @org.springframework.beans.factory.annotation.
     Qualifier(value=loggerProxySpring)}
     表示希望返回IuserDao,实际却是loggerProxySpring这个实例
     所以构造方法无法处理Proxy实例化这一步

     */


   //构造方法无法实例化Proxy所返回的被代理对象所实现的接口,所以要这么写
   public static  Object getInstance(Object o) {
        LoggerProxySpring proxy = new LoggerProxySpring();
        proxy.target = o;
      return   Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),proxy);
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            //对带有指定参数args的指定对象target调用由此 Method 对象表示的底层方法

        //如果方法是list,不用打印日志信息
       /* if (!"list".equals(method.getName()) || !"search".equals(method.getName())){
            Logger.log("Before:进行了相关操作");
        }*/

       //注解  ——对加了注解的方法输出日志
         Log_meice lo = method.getAnnotation(Log_meice.class);
         if(lo != null) {
             Logger.log("Before:进行了操作:"+lo.value());
         }

     Object obj =   method.invoke(target,args);
     Logger.log("After:进行了相关操作");
        return obj;
    }



}

配置spring.xml

<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="com.hmc.spring"/>

    <!--配置动态代理-->
    <bean name="loggerProxySpring" class="com.hmc.spring.proxy.LoggerProxySpring"  factory-method="getInstance" >

        <constructor-arg   value="userJdbcDao"></constructor-arg>
    </bean>

    <!--配置BookDao的动态代理-->
    <bean name="bookProxySpring" class="com.hmc.spring.proxy.LoggerProxySpring" factory-method="getInstance">
        <constructor-arg value="bookDao"></constructor-arg>
    </bean>


</beans>

弊端:无法实现指定方法输出日志。
一般,查询方法不加日志,但是增修、修改、删除加日志,查询方法不加日志。如何处理?
做个判断:

if ("list".equals(method.getName())){
    Logger.log("Before:进行了相关操作");
}

如果方法名不一致呢?加入多个判断?
//对带有指定参数args的指定对象target调用由此 Method 对象表示的底层方法

if (!"list".equals(method.getName()) || !"search".equals(method.getName())){
    Logger.log("Before:进行了相关操作");
}  

你能穷尽所有查的方法么?只要名字一变化,就不一样了…所以注解最方便:

2)注解方式实现AOP

@AspectJ-简化配置
有木有觉!得上面的动态代理很麻烦,比较复杂?其实笔者测试的时候,不甚顺利。注解方式实现AOP真的是So Easy!

(1)导入包aspectj包
只有导入这个包,才能用@AspectJ这个注解,不然没有呢

<!--导入AspectJWeaver包-->
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.12</version>
  </dependency>

(2)开启spring AOP支持

xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

要想开启支持,就需要有这个标签可以用,头部只有加入spring-aop,才会有下面的标签。

<!--开启spring AOP 支持-->
<aop:aspectj-autoproxy/>

(3)定义切面

@Component
@Aspect
public class LoggerProxy {

}

在代理类头部只加上@Aspect是不够的,还需要加上@Component
* @Aspect表明这是个切面类,里面会定义切入点。
@Component表明这个类在bean中所处的位置
* 因为它不属于Repository\Service\Controller

(4)定义通知

 /**
  * 前置通知
  *表达式匹配规则:
  * 第一个*:方法的修饰符(方法的返回类型)
  * 第二个*:service包下面的任意类
  * 第三个*:service包下面的任意类的任意方法
  * ..*表示service包下面的包的任意类
  *
  */
 @Before("execution(* com.hmc.spring.service.*.add*(..))  || " +
         "execution(* com.hmc.spring.service.*.del*(..)) ")
 public void BeforeMethod() {
        Logger.log("<<< 在调用方法前执行");
 }


 /**
  * 后置通知
  */
@After("execution(* com.hmc.spring.service.*.*(..))")
public void AfterMethod() {
     Logger.log("在方法之后调用>>>");
    //Logger.log("<<<环绕通知>>>");
}

/**
 * 环绕方法
 * 光加@Around是不行的,不会环绕
 */
@Around("execution(* com.hmc.spring.service.*.*(..))")
public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
    Logger.log("<<<方法前后都会执行>>>");
    pjp.proceed();
    Logger.log("<<<方法前后都会执行>>>");
}

/**
 * 测试异常执行通知
 * AfterReturnning
 * 只有方法正常执行,才会调用
 */
@AfterReturning("execution(* com.hmc.spring.service.*.*(..))")
public void afterReturnning() {
    Logger.log("方法抛出异常之后才执行");
}


/**
 * AfterThrowing表明
 * 方法只有出现异常,才能看到这个日志
 */
@AfterThrowing("execution(* com.hmc.spring.service.*.*(..))")
public void afterThrowing() {
    Logger.log("方法抛出异常才能看到我");
}

//连接点Joinpoint
可以更加精细化输出调用方法名等信息


@After("execution(* com.hmc.spring.service.*.*(..))")
public void AfterMethod(JoinPoint jp) {
    System.out.println("正在执行的方法是:"+jp.getSignature().getName());
     Logger.log("在方法之后调用>>>");
    //Logger.log("<<<环绕通知>>>");
}
 /**
  * JoinPoint 可以输出执行方法的名称等详细信息
  * org.aspectj.lang.JoinPoint;
  *
  * 运行结果:
  * 十一月 06, 2017 12:36:40 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
  信息: Loading XML bean definitions from class path resource [spring.xml]
  正在执行的方法是:save
  Mon Nov 06 00:36:41 CST 2017 在方法之后调用>>>

  java.lang.NullPointerException
  *
  *
  * 有什么用?根据这个可以快捷找到哪个方法执行异常
  * 以及其他更加精细化操作
  */

3)XML配置方式实现AOP

注解有注解的好处,但是过多注解,也让人不知所云,而且注解最大弊端就是侵入性,直接改源代码去了,这时候配置就出场了。大型项目很多用配置,便于修改,结构清晰。

1、开启AOP支持

 xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop                http://www.springframework.org/schema/aop/spring-aop.xsd

2、spring.xml中配置

<!--为了可以使用注解,加入context头部信息并配置注解-->
<context:component-scan base-package="com.hmc.spring"/>

<!--    XML配置AOP-->

<aop:config>
    <!--配置切面-->
    <aop:aspect ref="loggerProxy">
        <!--配置切入点-->
        <aop:pointcut id="allMethod" expression="execution(* com.hmc.spring.service.*.*(..))"  />
        <!--<aop:before method="BeforeMethod" pointcut-ref="allMethod"/>-->
        <aop:after method="AfterMethod" pointcut-ref="allMethod"/>
    </aop:aspect>
</aop:config>

测试:

package com.hmc.spring;
import com.hmc.spring.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * User:Meice
 * 2017/11/6
 */
public class SpringTest {
    private static ApplicationContext ac;
    static {
         ac = new ClassPathXmlApplicationContext("spring.xml");

    }

    @Test
    public void test() {
     IUserService ius =   ac.getBean("userService", IUserService.class);
     ius.save();

    }

}

运行结果:

十一月 06, 2017 8:44:15 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring.xml]
使用JDBC增加用户...
Mon Nov 06 08:44:17 CST 2017    方法之后调用》》》

六、总结


1、构造方法注入,通过constructor-org来注入;

2、自动装配与注解。
在spring.xml头部加入context==》扫描加入注解的包==》主要有:@Component 通用的,还是有用的,比如Proxy那个类,就要加上。@Repository注解Dao层,
@Service注解Service层;@Controller层, @Autowired自动装配(byName byType);@Qualifier(value =”“)表明具体应用的类
非常方便,从此不用再配置。注解一旦加上,就代表已经实例化。

3、设计模式
就是把所有的代码结构化分层,每一层职责明确。不论项目多么复杂,项目结构清晰明了。Model层
就是JavaBean,业务类的实体类;Dao层负责数据持久化,和数据库接入;Service层调用Dao层方法,实现
复杂的业务逻辑处理,Controller层主要做三件事:处理页面请求并接收参数、调用Service层方法、页面跳转。
各层层级关系明朗:Controller==>Service==>Dao 上层依赖于下层,下层为上层提供服务。

4、自定义注解
新建一个@Annotation类==》设置默认值==》通过元注解定义注解具体作用域==》搞定!

5、AOP实现3中方式

1)代理模式

(1)静态代理-类似复制一个类,然后加入想要织入的功能;
(2)动态代理—本质还是复制了这个类,只是通过这几个步骤实现:新建一个类,实现接口InvocationHandler,重写方法;定义代理人和代理产品,通过构造方法赋值产品; ==>method.invoke实现方法的复制==》Proxy.newInstance实例话这个代理类,返回一个接口。

2)注解方式
spring.xml中加入头文件aop==》开启注解支持==》创建代理类,@Aspect定义切面;@Before等定义切入点及通知==》测试运行

3)XML方式
通过配置切面、切入点即可。就这么简单!


好了,午安!各位读者,下期再会!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值