spring笔记

转摘于https://blog.csdn.net/column/details/sprintgnote.html

1、spring 资源抽象接口下常用实现类

ClassPathResource 类路径下的资源,以相对类路径方式表示 classpath:
FileSystemResource 文件系统资源,以文件系统路径方式表示
ServletContextResource web上下文中的资源,以相对于web应用根目录的路径加载资源
UrlResource 封装了java.net.URL,访问以URL表示的资源 file: http:// ftp://

PathMachingResourcePatternResolver ResourcePatternResolve标准实现类,多通过此类加载资源

2、Bean

xml基础配置
<bean id="bean_id" name="bean_name" class="class_name" >
<property name="properties_name" value="properties_value" lazy-init="default/true/false" scope="singleton/ prototype/request/session"/>
</bean>

引用外部Bean
<bean id="bean_1" class="xxx"></bean>
<bean id="bean_2" class="zzz">
<property name="ref_bean_name" ref="bean_1" />
</bean>

自动装配
<bean autowire="no/byName/byType/constructor/audodetect/default">

注解
<context:component-scan bese-package="xxx.xxx">
包含特定的类
<context:include-filter />
去除特定的类
<context:exclude-filter />

3、增强类型

前置增强#BeforeAdive 在目标方法前实施增强
后置增强#AfterReturningAdvice 在目标方法后实施增强
环绕增强#MethodInterceptor 在目标方法执行前后实施增强
异常抛出增强#ThrowsAdvice 在目标方法抛出异常后实施增强
引介增强#IntroductionInterceptor 在目标类中添加方法和属性

增强置入顺序
1. 前置增强->越先织入
2. 后置增强->越后织入
3. 最终增强->越后织入
4. 环绕增强->调用原方法之前的部分先织入,调用原方法之后的部分后织入


1# 配置代理接口
public interface Target {
String say(String str);
}
2# 定义被代理对象
public class ITarget implements Target {
@Override
public String say(String _str) {
return "return val";
}
}
3# 配置增强
import org.springframework.aop.MethodBeforeAdvice
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable{
if(target instanceof ITarget) {
System.out.println("before advice: " + (method.getName() + " executed") + "params " + args);
}
}
}
#####################################
import org.springframework.aop.AfterReturningAdvice
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnVal, Method method, Object[] args, Object target) throws Throwable {
if(target instanceof ITarget) {
System.out.println("after advice: " + "invoke method: " + method.getName() + " and return value: " + returnval);
}
}
}
#####################################
public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getArguments()[0] + "——" +
invocation.getStaticPart() + "——" +
invocation.getThis().getClass() + "——" +
invocation.getMethod().getName());
invocation.proceed();//反射调用目标对象方法
System.out.println("环绕增强调用结束");
return "I'm around return value";
}
#####################################
import org.springframework.aop.ThrowsAdvice;
public class ExceptionAdvice implements ThrowsAdvice {
public void AfterThrowing(SQLException e){
System.out.println(e.getMessage());
}
public void AfterThrowing(RuntimeException e){
System.out.println(e.getMessage());
}
public void AfterThrowing(Method method, Object[] args, Object target,SQLException e){
System.out.println(e.getMessage());
}
}
#####################################
4# 配置代理对象ProxyFactoryBean
<!-- 配置被代理对象 -->
<bean id="myTarget" class="xxx.xxx.ITarget" />
<!--配置前置增强-->
<bean id="myBeforeAdvice class= "xxx.xxx.BeforeAdvice"/>
<!--配置后置增强-->
<bean id="myAfterAdvice class= "xxx.xxx.AfterAdvice"/>
<!--配置代理对象-->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFacotryBean" >
<!--配置代理接口-->
<property name="proxyInterfaces" value="xxx.xxx.Target" />
<!--代理目标对象实现的接口,把通知置入代理对象-->
<property name="interceptorNames" >
<list>
<idref bean="myBeforeAdvice" />
<idref bean="myAfterAdvice" />
</list>
</property>
<!--代理的目标对象-->
<property name="targetName" value="myTarget" />
</bean>
=====================@AspectJ===============================
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeAdvice {
@Before("execution(public String xxx.xxx.ITarget.say(String))")
public void before(JoinPoint joinPoint) throws Throwable {
System.out.println("前置日志记录: "
+ ((Target) joinPoint.getTarget()).getName() + "调用了"
+ joinPoint.getSignature().getName() + "方法,传入参数为:"
+ joinPoint.getArgs()[0]);
}
}
################################
<aop:aspectj-autoproxy />
<bean class="xxx.xxx.BeforeAdvice" />
<bean id="target" class="xxx.xxx.ITarget" />
################################
前置增强 @Before(value,argNames)
value:定义切点 argsName:指定注解所标注的增强方法的参数名,多个参数用都好隔开
后置增强 @AfterReturning(value/pointcut,returning,argNames)
value/pointcut:定义切点,若同时定义,value会被pointcut覆盖 returning:将目标对象的方法绑定到增强的方法中
异常增强
AfterThrowing(value/pointcut,throwing,argNames) throwing:将抛出的异常绑定到增强方法中
最终(final)增强
@DeclareParents(value,defaultImpl)
################################
涉及到的通配符主要有3种:
1. * 匹配任意一个元素,如返回值,某个包,某个类,某个方法等
2. .. 匹配多个元素,表示类时要和*联合使用(如com.yc.controller..*定位controller包下的所有类 ),表示入参时则单独使用(com.yc.controller.UserController.login(..)定位与对应包、类下参数类型数量任意的名为login的方法,这在使用多态特性和不确定入参时常用)
3. + 按类型匹配指定类及其子类
################################
模拟通过注解方式记录用户日志
1# 自定义注解
@Retention(RetentionPolicy.CLASS)//生命注释保留时长,这里无需反射使用,使用CLASS级别
@Target(ElementType.METHOD)//生命可以使用此注解的元素级别类型(如类、方法变量等)
public @interface NeedRecord {}
2# 定义切面
@Aspect
public class Annotation_aspect {
@AfterReturning("@annotation(test.aop2.NeedRecord)")//指向注解类
public void Record(JoinPoint joinPoint){//切点入参。
System.out.println("日志记录:用户" +joinPoint.getArgs()[0] + "在" + new SimpleDateFormat("yyyy-MM-dd hh:mm;ss").format(new Date()) + "调用了"+ joinPoint.getSignature()+"方法" );
}
}
3# 定义目标对象
@NeedRecord
public void login(String name){
System.out.println("I'm "+name+" ,I'm logining");
}
4# 配置
<aop:aspectj-autoproxy /> <!-- 使@AspectJ注解生效 -->
<bean class="test.aop2.Annotation_aspect" /><!-- 注册切面,使AOP自动识别并进行AOP方面的配置 -->
<bean id="userController" class="test.aop2.UserController" /><!-- 注册目标对象 -->
5# 测试
public static void main(String args[]){
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:xxx/xxx/aop.xml");
UserController userController = (UserController) ac.getBean("userController");
userController.login("zenghao");
}


4、 事务配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" /> </bean>
<!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager"><!--事务的增强配置-->
<tx:attributes>
<!--name="add*"相当于我们的函数切点表达式,匹配以add开头的方法,使用REQUIRED的事务传播行为-->
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="search*" propagation="SUPPORTS" />
<tx:method name="*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
<aop:config><!--aop命名空间配置的开始-->
<aop:pointcut id="transactionPointcut"
<!--这里也是切点,和前面的<tx:method name="add*>取交来定位连接点-->
<aop:advisor pointcut-ref="transactionPointcut"
advice-ref="transactionAdvice" />
</aop:config>

5、异步方式实现spring事件,以用户注册时发送短信与邮件为示例

1# 定义事件源(在spring中,所有事件都必须扩展抽象类ApplicationEvent,同时将事件源作为构造函数参数)

public class SendEmailEvent extends ApplicationEvent {

private String emailAddress;

public SendEmailEvent(Object source, String _emailAddress) {
//source 指发送事件的根源
super(source);
this.emailAddress = _emailAddress;
}

public String getEmailAddress() {
return emailAddress;
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
public class SendMsgEvent extends ApplicationEvent {

private String phone;

public sendMsgEvent(Object source, String _phone) {
super(source);
this.phone = _phone;
}

public String getPhone() {
return phone;
}
}

2# 定义事件监听器,实现ApplicationListener接口

public class RegisterListener implements ApplicationListener {

if(event instanceof SendEmailEvent){//如果是发邮箱事件
System.out.println("正在向" + ((SendEmailEvent) event).getEmailAddress()+ "发送邮件......");//模拟发送邮件事件
try {
Thread.sleep(1* 1000);//模拟请求邮箱服务器、验证账号密码,发送邮件耗时。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("邮件发送成功!");
}else if(event instanceof sendMessageEvent){//是发短信事件
event = (sendMessageEvent) event;
System.out.println("正在向" + ((sendMessageEvent) event).getPhoneNum()+ "发送短信......");//模拟发送邮短信事件
try {
Thread.sleep(1* 1000);//模拟发送短信过程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("短信发送成功!");
}

}
备注,也可通过泛型方式
/******************通过泛型配置实例如下******************/
public class RegisterListener implements ApplicationListener<SendEmailEvent> {//这里使用泛型
@Override//因为使用了泛型,我们的重写方法入参事件就唯一了。
public void onApplicationEvent(SendEmailEvent event) {
.....
}
....
}

3# 定义事件发布者,实现ApplicationEventPublisherAware接口

public class UserService implements ApplicationEventPublisherAware {

private ApplicationEventPublisher applicationEventPublisher;

//也可以通过实现ApplicationContext接口
//private ApplicationContext applicationContext;

@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.applicationEvenetPublisher = publisher;
}

public void doLogin(String email, String phone) throws InterruptedExecption {
Thread.sleep(200);//模拟用户注册业务
SendEmailEvent emailEvent = new SendEmailEvent(this, email);
SendMsgEvent msgEvent = new SendMsgEvent(this, phone);
applicationEventPublisher.publishEvent(emailEvent);
applicationEventPublisher.publishEvent(msgEvent);
}
}


4# 在IOC容器注册监听器
<!-- 注册事件监听器,应用上下文将会识别实现了ApplicationListener接口的Bean,并在特定时刻将所有的事件通知它们-->
<bean id="RegisterListener" class="test.event.RegisterListener" />
<!-- 注册我们的发布者 -->
<bean id="userService" class="test.event.UserService" />

5# 测试

public static void main(String args[]) throws InterruptedException{
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:test/event/event.xml");
UserService userService = (UserService) ac.getBean("userService");
Long beginTime = System.currentTimeMillis();
userService.doLogin("zenghao@google.com","12345678911");//完成注册请求
System.out.println("处理注册相关业务耗时" + (System.currentTimeMillis() - beginTime )+ "ms");
System.out.println("处理其他业务逻辑");
Thread.sleep(500);//模拟处理其他业务请求耗时
System.out.println("处理所有业务耗时" + (System.currentTimeMillis() - beginTime )+ "ms");
System.out.println("向客户端发送注册成功响应");
}

测试发现比较耗时,改进方法异步
1# 容器添加task标签
<!--先在命名空间中增加我们的task标签,注意它们的添加位置xmlns 多加下面的内容:
xmlns:task="http://www.springframework.org/schema/task"
然后xsi:schemaLocation多加下面的内容
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd-->
<!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven/>

2# 事件监听器中添加@Async注解
@Async
public class RegisterListener implements ApplicationListener {
......
}

posted @ 2018-06-29 16:36  秋水秋色  阅读(153)  评论(0编辑  收藏  举报