热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

话说:各位读者早上好,上一篇博客初步了解了下Spring,这篇深入总结下。Hibernate、Struts2现在主流用得少了࿰

话说:

各位读者早上好,上一篇博客初步了解了下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中配置


<beans xmlns&#61;"http://www.springframework.org/schema/beans"xmlns:xsi&#61;"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&#61;"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean name&#61;"userJdbcDao" class&#61;"sdcom.hmc.spring.dao.UserJdbcDao">bean><bean name&#61;"userService" class&#61;"com.hmc.spring.service.UserService" autowire&#61;"constructor"><constructor-arg index&#61;"0" ref&#61;"userJdbcDao">constructor-arg>bean>beans>

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

二、自动装配

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

主要类型&#xff1a;no、 byName、byType、constructor

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

private IUserDao userJdbcDao;public IUserDao getUserJdbcDao() {return userJdbcDao;}public void setUserJdbcDao(IUserDao userJdbcDao) {this.userJdbcDao &#61; userJdbcDao;}

第二步&#xff1a;自动装配 加上autowire&#61;”byName”

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

注意&#xff1a;这里因为是byName,定义的属性userJdbcDao要和bean的name一致&#xff0c;否则就报错NullPointExcep&#xff0c;找不到嘛&#xff01;

2) byType

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

第一步&#xff1a;定义接口属性&#xff0c;并生成get set

private IUserDao userDao;public IUserDao getUserDao() {return userDao;} public void setUserDao(IUserDao userDao) {this.userDao &#61; userDao;}

第二步&#xff1a;自动装配 加入&#xff1a;autowire&#61;”byType”

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

But&#xff01;

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

java.lang.ExceptionInInitializerErrorCaused by: ....NoUniqueBeanDefinitionException: No qualifying bean of type &#39;com.hmc.spring.dao.IUserDao&#39; available: expected single matching bean but found 2: userJdbcDao,userHibernateDao

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

3) constructor

构造方法&#xff0c;顾名思义&#xff0c;之前的构造方法属性注入也可以通过autowire&#61;”constructor”来配置
第一步&#xff1a;定义接口类型属性和构造方法

private IUserDao userDao;public UserService() {}//构造方法初始化public UserService(IUserDao userDao) {this.userDao &#61; userDao;}

第二步&#xff1a;加入自动装配constructor

第二步&#xff1a;加入自动装配constructor<bean name&#61;"userJdbcDao" class&#61;"com.hmc.spring.dao.UserJdbcDao">bean><bean name&#61;"userService" class&#61;"com.hmc.spring.service.UserService" autowire&#61;"constructor">//这里神马也不用写&#xff01;bean>

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

<bean name&#61;"userJdbcDao" class&#61;"com.hmc.spring.dao.UserJdbcDao">bean><bean name&#61;"userHibernateDao" class&#61;"com.hmc.spring.dao.UserHibernateDao">bean><bean name&#61;"userService" class&#61;"com.hmc.spring.service.UserService" autowire&#61;"constructor">bean>

三、注解

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

1&#xff09;主要几个注解&#64;Repository &#64;Service &#64;Controller &#64;Autowired &#64;Qualifier 等

如何实现注解呢&#xff1f;

&#xff08;1&#xff09;开启注解支持
官方文档在spring.xml中加入头部信息

xmlns:context&#61;"http://www.springframework.org/schema/context"http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd

&#xff08;2&#xff09; 扫描加入注解的包

<context:component-scan base-package&#61;"com.hmc.spring"/>

&#xff08;3&#xff09;给相应业务类加上相应注解

Dao层&#64;Repositorypublic class UserDao implements IUserDao {}Service层&#64;Servicepublic class UserService implements IUserService {}Autowired实现自动装配&#64;Autowired&#xff08;默认byType&#xff09;private IUserDao userDao;可以使用Qualfier指定bean的名称&#64;Autowired&#64;Qualifier(value &#61; "userJdbcDao")——手动指定在哪个bean进行装配private IUserDao userDao;

如果生成了get() set()方法&#xff0c;就通过&#64;Resource方法注解&#xff0c;等同于&#64;Autowired &#43; &#64;Qualifier

private IUserDao userDao;public IUserDao getUserDao() {return userDao;}&#64;Resource(name &#61; "userHibernateDao")//生成set()方法&#xff0c;通过Resource( name&#61;""指定属性)public void setUserDao(IUserDao userDao) {this.userDao &#61; userDao;}

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

2&#xff09;自定义注解

我们不能总做使用者吧&#xff1f;如果可能&#xff0c;我们也要尽可能去创造。

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;&#64;Target({ElementType.METHOD}) //表示在元素上运行
&#64;Retention(RetentionPolicy.RUNTIME) //注解在运行时有效
public &#64;interface Log_meice {String value() default "";
}

2、加入元注解

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

3、测试

package com.hmc.spring.dao;
import com.hmc.spring.annotation.Log_meice;
public interface IUserDao {&#64;Log_meice("增加了用户")void add();&#64;Log_meice("更新了用户")void update();&#64;Log_meice("删除了用户")void del();void list();
}

四、设计模式

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

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

五、三种方式实现AOP

1&#xff09;经典方式&#xff1a;静态代理与动态代理
2&#xff09;注解方式
3&#xff09;XML配置方式

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

1&#xff09;经典方式&#xff1a;静态代理与动态代理

a、静态代理如何实现&#xff1f;
b、动态代理&#xff1f;

目的&#xff1a;UserService在调用Dao层add()方法时&#xff0c;为其增加日志信息。日志信息内容如下&#xff1a;

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()&#43;"--->"&#43;info);}}

a、静态代理如何实现&#xff1f;

package com.hmc.spring.dao;
import com.hmc.spring.log.Logger;
import org.springframework.stereotype.Repository;/*** User:Meice* 2017/11/5*/
&#64;Repository
public class UserProxyJdbcDao implements IUserDao {/*** 静态代理步骤&#xff1a;* 1、创建一个和要添加功能一模一样的Dao* 2、加入新增方法* 3、注解&#xff08;自动装配&#xff09;*/public void add() {System.out.println("使用JDBC新增了用户....");Logger.log("添加了用户");}public void update() {}public void del() {}public void list() {}
}

b、动态代理&#xff1f;

先单纯实现动态代理&#xff0c;不与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 &#61; o;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("嗯哈");// Logger.log("Before:进行了相关操作");Object obj &#61; method.invoke(target,args);// Logger.log("After:进行了相关操作");return obj;}public static void main(String[] args) {UserJdbcDao userJdbcDao &#61; new UserJdbcDao();//被代理对象LoggerProxy proxy &#61; new LoggerProxy(userJdbcDao); //得到代理对象/* IUserDao userDaoProxy &#61;(IUserDao)Proxy.newProxyInstance(UserJdbcDao.class.getClassLoader(),IUserDao.class.getInterfaces(),proxy);userDaoProxy.add();*//*** 运行结果&#xff1a;* java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.hmc.spring.dao.IUserDao*/IUserDao ud &#61;(IUserDao)Proxy.newProxyInstance(UserJdbcDao.class.getClassLoader(),UserJdbcDao.class.getInterfaces(),proxy);ud.add();/*** 以上整体执行流程是这样的&#xff1a;* ud.add()&#xff0c;ud表示指定的接口(IUserDao)的代理实例,&#xff0c;该接口将add()方法的调用指派到指定的调用处理程序-proxy* 调用处理程序就是指实现InvocationHandler接口的这个类&#xff0c;也就是这里的LoggerProxy,只要把它实例化——通过带参构造* 方法把被代理对象-UserJdbcDao传过去即可。** 最终&#xff0c;你看到的输出信息&#xff0c;就是这个类中invoke()方法体重输出的信息&#xff0c;而不是原有UserJdbcDao中的方法。* 因为方法已经通过Method的invoke方法从底层映射过来了。** 再说简单点&#xff1a;也就是通过2步走就把UserJdbcDao中的add()方法复制了一份到这个调用处理程序中。然后在这里* 加入我们需要增加的内容&#xff0c;而不改变原有方法。** 第一步&#xff1a;创建一个类&#xff0c;实现InvocationHandler接口&#xff0c;并实现方法。(这个类就是调用处理程序)* 第二步&#xff1a;通过Proxy这个类实例化该调用处理程序&#xff0c;实例化过程中就制定了代理产品-UserJdbcDao***/}}

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

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 &#61; o;Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this);}*//*** 构造方法无法返回Proxy实例化后被代理对象实现的接口就会报错&#xff1a; No qualifying bean of type &#39;com.hmc.spring.dao.IUserDao&#39; available: expected at least 1 bean whichqualifies as autowire candidate. Dependency annotations:{&#64;org.springframework.beans.factory.annotation.Autowired(required&#61;true), &#64;org.springframework.beans.factory.annotation.Qualifier(value&#61;loggerProxySpring)}表示希望返回IuserDao&#xff0c;实际却是loggerProxySpring这个实例所以构造方法无法处理Proxy实例化这一步*///构造方法无法实例化Proxy所返回的被代理对象所实现的接口&#xff0c;所以要这么写public static Object getInstance(Object o) {LoggerProxySpring proxy &#61; new LoggerProxySpring();proxy.target &#61; 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 &#61; method.getAnnotation(Log_meice.class);if(lo !&#61; null) {Logger.log("Before:进行了操作:"&#43;lo.value());}Object obj &#61; method.invoke(target,args);Logger.log("After:进行了相关操作");return obj;}}

配置spring.xml

<beans xmlns&#61;"http://www.springframework.org/schema/beans"xmlns:xsi&#61;"http://www.w3.org/2001/XMLSchema-instance"xmlns:context&#61;"http://www.springframework.org/schema/context"xsi:schemaLocation&#61;"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package&#61;"com.hmc.spring"/><bean name&#61;"loggerProxySpring" class&#61;"com.hmc.spring.proxy.LoggerProxySpring" factory-method&#61;"getInstance" ><constructor-arg value&#61;"userJdbcDao">constructor-arg>bean><bean name&#61;"bookProxySpring" class&#61;"com.hmc.spring.proxy.LoggerProxySpring" factory-method&#61;"getInstance"><constructor-arg value&#61;"bookDao">constructor-arg>bean>beans>

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

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

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

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

你能穷尽所有查的方法么&#xff1f;只要名字一变化&#xff0c;就不一样了…所以注解最方便&#xff1a;

2&#xff09;注解方式实现AOP

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

&#xff08;1&#xff09;导入包aspectj包
只有导入这个包&#xff0c;才能用&#64;AspectJ这个注解&#xff0c;不然没有呢

<dependency><groupId>org.aspectjgroupId><artifactId>aspectjweaverartifactId><version>1.8.12version>dependency>

&#xff08;2&#xff09;开启spring AOP支持

xmlns:aop&#61;"http://www.springframework.org/schema/aop"http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

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


<aop:aspectj-autoproxy/>

&#xff08;3&#xff09;定义切面

&#64;Component
&#64;Aspect
public class LoggerProxy {}

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

&#xff08;4&#xff09;定义通知

/*** 前置通知*表达式匹配规则&#xff1a;* 第一个*:方法的修饰符&#xff08;方法的返回类型&#xff09;* 第二个*:service包下面的任意类* 第三个*:service包下面的任意类的任意方法* ..*表示service包下面的包的任意类**/&#64;Before("execution(* com.hmc.spring.service.*.add*(..)) || " &#43;"execution(* com.hmc.spring.service.*.del*(..)) ")public void BeforeMethod() {Logger.log("<<<在调用方法前执行");}/*** 后置通知*/
&#64;After("execution(* com.hmc.spring.service.*.*(..))")
public void AfterMethod() {Logger.log("在方法之后调用>>>");//Logger.log("<<<环绕通知>>>");
}/*** 环绕方法* 光加&#64;Around是不行的&#xff0c;不会环绕*/
&#64;Around("execution(* com.hmc.spring.service.*.*(..))")
public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {Logger.log("<<<方法前后都会执行>>>");pjp.proceed();Logger.log("<<<方法前后都会执行>>>");
}/*** 测试异常执行通知* AfterReturnning* 只有方法正常执行&#xff0c;才会调用*/
&#64;AfterReturning("execution(* com.hmc.spring.service.*.*(..))")
public void afterReturnning() {Logger.log("方法抛出异常之后才执行");
}/*** AfterThrowing表明* 方法只有出现异常&#xff0c;才能看到这个日志*/
&#64;AfterThrowing("execution(* com.hmc.spring.service.*.*(..))")
public void afterThrowing() {Logger.log("方法抛出异常才能看到我");
}//连接点Joinpoint
可以更加精细化输出调用方法名等信息&#64;After("execution(* com.hmc.spring.service.*.*(..))")
public void AfterMethod(JoinPoint jp) {System.out.println("正在执行的方法是:"&#43;jp.getSignature().getName());Logger.log("在方法之后调用>>>");//Logger.log("<<<环绕通知>>>");
}/*** JoinPoint 可以输出执行方法的名称等详细信息* org.aspectj.lang.JoinPoint;** 运行结果&#xff1a;* 十一月 06, 2017 12:36:40 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [spring.xml]正在执行的方法是:saveMon Nov 06 00:36:41 CST 2017 在方法之后调用>>>java.lang.NullPointerException*** 有什么用&#xff1f;根据这个可以快捷找到哪个方法执行异常* 以及其他更加精细化操作*/

3&#xff09;XML配置方式实现AOP

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

1、开启AOP支持

xmlns:aop&#61;"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:component-scan base-package&#61;"com.hmc.spring"/><aop:config><aop:aspect ref&#61;"loggerProxy"><aop:pointcut id&#61;"allMethod" expression&#61;"execution(* com.hmc.spring.service.*.*(..))" /><aop:after method&#61;"AfterMethod" pointcut-ref&#61;"allMethod"/>aop:aspect>
aop:config>

测试&#xff1a;

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 &#61; new ClassPathXmlApplicationContext("spring.xml");}&#64;Testpublic void test() {IUserService ius &#61; ac.getBean("userService", IUserService.class);ius.save();}}

运行结果&#xff1a;

十一月 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、构造方法注入&#xff0c;通过constructor-org来注入&#xff1b;

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

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

4、自定义注解
新建一个&#64;Annotation类&#61;&#61;》设置默认值&#61;&#61;》通过元注解定义注解具体作用域&#61;&#61;》搞定&#xff01;

5、AOP实现3中方式

1&#xff09;代理模式

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

2&#xff09;注解方式
spring.xml中加入头文件aop&#61;&#61;》开启注解支持&#61;&#61;》创建代理类&#xff0c;&#64;Aspect定义切面&#xff1b;&#64;Before等定义切入点及通知&#61;&#61;》测试运行

3&#xff09;XML方式
通过配置切面、切入点即可。就这么简单&#xff01;



好了&#xff0c;午安&#xff01;各位读者&#xff0c;下期再会&#xff01;


推荐阅读
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 标题: ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
author-avatar
你的眼神16_884
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有