spring入门3.0
三 小黑子的springAOP开发
1. AOP简介
1.1 AOP的概念
1.2 AOP思想的实现方案
1.3 模拟AOP思想实现的基础代码
1.4 AOP的相关概念
2. 基于xml配置的AOP
2.1 XML方式AOP快速入门
2.2 XML方式AOP配置详解
2.3 xml方式AOP的原理解析
3. 基于注解配置的AOP
3.1、注解方式AOP基本使用
3.2 注解方式AOP配置详解
3.3 注解方式AOP原理解析
三 小黑子的springAOP开发
1. AOP简介
1.1 AOP的概念
AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程
再打比方地说面向切面就是:
有一台手机,用面向对象的思想去设计这个手机。手机内部有一些对应的属性,屏幕、硬件什么的都是静态属性,但是也有动态行为:打电话和照相等,把其封装成相应的方法。要打电话的方法,就能执行其功能。这个就是对各个事务进行一个纵向的抽象:这个事务包含哪些动态的行为、哪些静态的属性,都可以用方法和属性去表达。可是,在众多对象当中,可能要抽取每个对象当中的一部分功能,再临时组装成一个对象进行执行。
1.2 AOP思想的实现方案
代理技术 动态代理技术,在运行期间,对目标对象的方法进行增强,代理对象同名方法内可以执行原有逻辑的同时嵌入执行其他增强逻辑或其他对象的方法
1.3 模拟AOP思想实现的基础代码
其实在之前学习BeanPostProcessor时,在BeanPostProcessor的after方法中使用动态代理对Bean进行了增强,实际存储到单例池singleObjects中的不是当前目标对象本身,而是当前目标对象的代理对象Proxy,这样在调用目标对象方法时,实际调用的是代理对象Proxy的同名方法,起到了目标方法前后都进行增强的功能,对该方式进行一下优化,将增强的方法提取出去到一个增强类中,且只对com.itheima.service.impl包下的任何类的任何方法进行增强
public interface UserService {
void show1 ( ) ;
void show2 ( ) ;
}
public class UserServiceImpl implements UserService {
@Override
public void show1 ( ) {
System . out. println ( "show1......" ) ;
}
@Override
public void show2 ( ) {
System . out. println ( "show2......." ) ;
}
}
public class MyAdvice {
public void beforeAdvice ( ) {
System . out. println ( "前置的增强。。。" ) ;
}
public void afterAdvice ( ) {
System . out. println ( "后置的增强。。。" ) ;
}
ublic class MockAopBeanPostProcessor implements BeanPostProcessor , ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization ( Object bean, String beanName) throws BeansException {
if ( bean. getClass ( ) . getPackage ( ) . getName ( ) . equals ( "com.itheima.service.impl" ) ) {
Object beanProxy = Proxy . newProxyInstance (
bean. getClass ( ) . getClassLoader ( ) ,
bean. getClass ( ) . getInterfaces ( ) ,
( Object proxy, Method method, Object [ ] args) -> {
MyAdvice myAdvice = applicationContext. getBean ( MyAdvice . class ) ;
myAdvice. beforeAdvice ( ) ;
Object result = method. invoke ( bean, args) ;
myAdvice. afterAdvice ( ) ;
return result;
}
) ;
return beanProxy;
}
return bean;
}
@Override
public void setApplicationContext ( ApplicationContext applicationContext) throws BeansException {
this . applicationContext = applicationContext;
}
}
< bean id = " userService" class = " com.itheima.service.impl.UserServiceImpl" > bean>
< bean id = " myadvice" class = " com.itheima.advice.MyAdvice" > bean>
< bean class = " com.itheima.MockAopBeanPostProcessor" > bean>
@Test
public void aopTest1 ( ) {
ApplicationContext app = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
UserService userService = app. getBean ( UserService . class ) ;
userService. show1 ( ) ;
}
1.4 AOP的相关概念
概念
单词
解释
目标对象
Target
被增强的方法所在的对象
代理对象
Proxy
对目标对象进行增强后的对象,客户端实际调用的对象
连接点
Joinpoint
目标对象中可以被增强的方法
切入点
Pointcut
目标对象中实际被增强的方法
通知 \ 增强
Advice
增强部分的代码逻辑
切面
Aspect
增强和切入点的组合
织入
Weaving
将通知和切入点组合动态组合的过程
2. 基于xml配置的AOP
2.1 XML方式AOP快速入门
前面编写的AOP基础代码还是存在一些问题的,主要如下
if ( bean. getClass ( ) . getPackage ( ) . getName ( ) . equals ( "com.itheima.service.impl" ) ) {
Object beanProxy = Proxy . newProxyInstance (
bean. getClass ( ) . getClassLoader ( ) ,
bean. getClass ( ) . getInterfaces ( ) ,
( Object proxy, Method method, Object [ ] args) -> {
MyAdvice myAdvice = applicationContext. getBean ( MyAdvice . class ) ;
myAdvice. beforeAdvice ( ) ;
Object result = method. invoke ( bean, args) ;
myAdvice. afterAdvice ( ) ;
return result;
}
) ;
return beanProxy;
缺点:
被增强的包名在代码写死了
通知对象的方法在代码中写死了
通过配置文件的方式去解决上述问题
配置哪些包、哪些类、哪些方法需要被增强
配置目标方法要被哪些通知方法所增强,在目标方法执行之前还是之后执行增强
配置方式的设计、配置文件(注解)的解析工作,Spring已经帮我们封装好了
xml方式配置AOP的步骤:
导入AOP相关坐标;
< dependency>
< groupId> org.aspectj groupId>
< artifactId> aspectjweaver artifactId>
< version> 1.9.6 version>
dependency>
准备目标类、准备通知类,并配置给Spring管理;
< bean id = " userService" class = " com.itheima.service.impl.UserServiceImpl" > bean>
< bean id = " myadvice" class = " com.itheima.advice.MyAdvice" > bean>
配置切点表达式(哪些方法被增强); 配置切点表达式的时候,就要用到spring对应的一个命名空间,用到aop的标签
配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)。
< beans xmlns = " http://www.springframework.org/schema/beans"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns: aop= " http://www.springframework.org/schema/aop"
xsi: schemaLocation= "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
" >
< bean id = " userService" class = " com.itheima.service.impl.UserServiceImpl" > bean>
< bean id = " myadvice" class = " com.itheima.advice.MyAdvice" > bean>
< aop: config>
< aop: pointcut id = " myPointcut" expression = " execution(void com.itheima.service.impl.UserServiceImpl.show1())" />
< aop: aspect ref = " myadvice" >
< aop: before method = " beforeAdvice" pointcut-ref = " myPointcut" > aop: before>
aop: aspect>
aop: config>
beans>
@Test
public void aopTest1 ( ) {
ApplicationContext app = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
UserService userService = app. getBean ( UserService . class ) ;
userService. show1 ( ) ;
}
2.2 XML方式AOP配置详解
xml配置AOP的方式还是比较简单的,下面看一下AOP详细配置的细节:
切点表达式的配置方式
可以配置多个切点
< aop: config>
< aop: pointcut id = " mtPointcut" expression = " execution(void com.itheima.service.Impl.UserServiceImpl.show1())" />
< aop: pointcut id = " mtPointcut2" expression = " execution(void com.itheima.service.Impl.UserServiceImpl.show2())" />
aop: config>
pointcut
属性可以再后面直接写上要结合的切点
< aop: config>
< aop: pointcut id = " mtPointcut" expression = " execution(void com.itheima.service.Impl.UserServiceImpl.show1())" />
< aop: aspect ref = " myadvice" >
< aop: before method = " beforeAdvice" pointcut-ref = " mtPointcut" > aop: before>
< aop: after method = " afterAdvice" pointcut = " execution(void com.itheima.service.Impl.UserServiceImpl.show1())" > aop: after>
aop: aspect>
aop: config>
切点表达式的配置语法
execution ( [ 访问修饰符] 返回值类型 包名. 类名. 方法名( 参数) )
其中,
访问修饰符可以省略不写;
返回值类型、某一级包名、类名、方法名可以使用*
表示任意;
包名与类名之间使用单点.
表示该包下的类,使用双点..
表示该包及其子包下的类;
参数列表可以使用两个点..
表示任意参数。
execution ( public void com. itheima. aop. TargetImpl. show ( ) )
execution ( * com. itheima. aop. TargetImpl. *( . . ) )
execution ( * com. itheima. aop. *. *( . . ) )
execution ( * com. itheima. aop. . *. *( . . ) )
execution ( * * . . *. *( . . ) )
通知名称
配置方式
执行时机
前置通知
目标方法执行之前执行
后置通知
目标方法执行之后执行,目标方法异常时,不在执行
环绕通知
目标方法执行前后执行,目标方法异常时,环绕后方法不在执行
异常通知
目标方法抛出异常时执行
最终通知
不管目标方法是否有异常,最终都会执行
< beans xmlns = " http://www.springframework.org/schema/beans"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns: aop= " http://www.springframework.org/schema/aop"
xsi: schemaLocation= "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
" >
< bean id = " userService" class = " com.itheima.service.impl.UserServiceImpl" > bean>
< bean id = " myadvice" class = " com.itheima.advice.MyAdvice" > bean>
< aop: config>
< aop: pointcut id = " myPointcut2" expression = " execution(* com.itheima.service.impl.*.*(..))" />
< aop: aspect ref = " myadvice" >
< aop: around method = " around" pointcut-ref = " myPointcut2" > aop: around>
< aop: after-throwing method = " afterThrowingAdvice" pointcut-ref = " myPointcut2" > aop: after-throwing>
< aop: after method = " afterAdvice" pointcut-ref = " myPointcut2" > aop: after>
aop: aspect>
aop: config>
beans>
通知方法再被调用时,Spring可以为其传递一些必要的参数
参数类型
作用
JoinPoint
连接点对象,任何通知都可使用,可以获得当前目标对象、目标方法参数等信息
ProceedingJoinPoint
JoinPoint子类对象,主要是在环绕通知中执行proceed(),进而执行目标方法
Throwable
异常对象,使用在异常通知中,需要在配置文件中指出异常对象名称
public void 通知方法名称( JoinPoint joinPoint) {
system. out. println ( joinPoint. getArgs ( ) ) ;
system. out. println ( joinPoint. getTarget ( ) ) ;
System . out. println ( joinPoint. getstaticPart ( ) ) ;
}
public void afterThrowing ( JoinPoint joinPoint, Throwable th) {
System . out. println ( "异常对象是:" + th+ "异常信息是:" + th. getMessage ( ) ) ;
}
< aop: after-throwing method = " afterThrowing" pointcut-ref = " myPointcut" throwing = " th" />
spring定义了一个Advice接口,实现了该接口的类都可以作为通知类出现
public interface Advice {
}
AOP配置的两种语法形式不同点:
语法形式不同:
advisor是通过实现接口来确认通知的类型
aspect是通过配置确认同的类型,更加灵活
科配置的切面数量不同:
一个advisor只能配置一个固定通知和一个切点表达式
一个aspect可以配置多个通知和多个切点表达式任意组合
使用场景不同
允许随意搭配情况下可以使用aspect进行配置
如果通知类型单一、切面单一的情况下可以使用advisor进行配置
在通知类型已经固定,不用人为指定通知类型时,可以使用advisor进行配置,例如后面要学习的spring事务控制的配置
2.3 xml方式AOP的原理解析
xml方式AOP的原理解析
通过xml方式配置AOP时,引入AOP的命名空间,根据讲解,要去spring-aop包下的META-INF,再去找spring.handlers文件 最终加载的是AopNamespaceHandler,该Handler的init方法中注册了config标签对应的解析器
this . registerBeanDefinitionParser ( "config" , new ConfigBeanDefinitionParser ( ) ) ;
以ConfigBeanDefinitionParser作为入口进行源码剖析,最终会注册一个AspectJAwareAdvisorAutoProxyCreator进入到Spring容器中,那该类作用是什么呢?看一下集成体系图
AspectJAwareAdvisorAutoProxyCreator的上上级父类AbstractAutoProxyCreator中的postProcessAfterlnitialization方法
public Object postProcessAfterInitialization ( @Nullable Object bean,String beanName) {
if ( bean != nul1) {
Object cacheKey = this . getCacheKey ( bean. getClass ( ) , beanName) ;
if ( this . earlyProxyReferences. remove ( cacheKey) != bean) {
return this . wrapIfNecessary ( bean, beanName, cacheKey) ;
}
}
return bean;
}
通过断点方式观察,当bean是匹配切点表达式时,this.wraplfNecessary(bean, beanName, cacheKey)返回的是一个JDKDynamicAopProxy
可以在深入一点,对wraplfNecessary在剖析一下,看看是不是我们熟知的通过JDK的 Proxy.newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler h)的方式创建的代理对象呢? 经过如下一系列源码跟踪
2.3.1 AOP底层两种生成Proxy的方式
动态代理的实现的选择,在调用getProxy()方法时,我们可选用的AopProxy接口有两个实现类,如上图,这两种都是动态生成代理对象的方式,一种就是基于JDK的,一种是基于Cglib的
代理技术
使用条件
配置方式
JDK动态代理技术
目标类有接口,是基于接口动态生成实现类的代理对象
目标类有接口的情况下,默认方式
Cglib
动态代理技术
目标类无接口且不能使用final修饰,是基于被代理对象动态生成子对象为代理对象 目标类无接口时,默认使用该方式;目标类有接口时,手动配置
下面看Cglib基于超类的动态代理:
Target target = new Target ( ) ;
Advices advices = new Advices ( ) ;
Enhancer enhancer = new Enhancer ( ) ;
enhancer. setSuperclass ( Target . class ) ;
enhancer. setCallback ( ( MethodInterceptor ) ( o, method, objects, methodProxy) -> {
advices. before ( ) ;
object result = method. invoke ( target, objects) ;
advices. afterReturning ( ) ;
return result;
} ) ;
Target tagetProxy = ( Target ) enhancer. create ( ) ;
String result = targetProxy. show ( "haohao" ) ;
3. 基于注解配置的AOP
3.1、注解方式AOP基本使用
Spring的AOP也提供了注解方式配置,使用相应的注解替代之前的xml配置,xml配置AOP时,我们主要配置了三部分:目标类被Sprina容器管理、通知类被Spring管理、通知与切点的织入(切面),如下:
< bean id = " target" class = " com.itheima.aop.TargetImpl" > bean>
< bean id = " advices" class = " com.itheima.aop.Advices" > bean>
< aop: config proxy-target-class = " true" >
< aop: aspect ref = " advices" >
< aop: around method = " around" pointeut = " execution(* com.itheima.aop.*.*(..))" />
aop: aspect>
aop: config>
配置aop,其实配置aop主要就是配置通知类中的哪个方法(通知类型)对应的切点表达式是什么
注解@Aspect
、@Around
需要被Spring解析,所以在Spring核心配置文件中需要配置aspectj
的自动代理
< aop: aspectj-autoproxy>
3.2 注解方式AOP配置详解
各种注解方式通知类型
@Before ( "execution( *com. itheima.aop.*.*(..))" )
public void before ( JoinPoint joinPoint) { }
@AfterReturning ( "execution(* com.itheima.aop.*.*(..))" )
public void afterReturning ( JoinPoint joinPoint) { }
@Around ( "execution (* com.itheima.aop.*.*(..))" )
public void around ( ProceedingJoinPoint joinPoint) throws Throwable { }
@AfterThrowing ( "execution(* com.itheima.aop.*.*(..))" )
public void afterThrowing ( JoinPoint joinPoint) { }
@After ( "execution(* com.itheima.aop.*.*(..))" )
public void after ( JoinPoint joinPoint) { }
@Component
@Aspect
public class MyAdvice {
@Pointcut ( "execution(* com.itheima.service.impl.*.*(..))" )
public void pointcut ( ) { } ;
@Before ( "MyAdvice.pointcut()" )
public void before ( ) {
System . out. println ( "前置增强" ) ;
}
@AfterReturning ( "execution(* com.itheima.service.impl.*.*(..))" )
public void afterreturning ( ) {
System . out. println ( "后置增强" ) ;
}
@Around ( "MyAdvice.pointcut()" )
public Object around ( ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System . out. println ( "环绕前增强。。。" ) ;
Object proceed = proceedingJoinPoint. proceed ( ) ;
JoinPoint. StaticPart staticPart = proceedingJoinPoint. getStaticPart ( ) ;
Object target = proceedingJoinPoint. getTarget ( ) ;
System . out. println ( "表达式:" + staticPart) ;
System . out. println ( "当前目标对象为:" + target) ;
System . out. println ( "环绕后增强。。。" ) ;
return proceed;
}
@AfterThrowing ( "MyAdvice.pointcut()" )
public void afterThrowAdvice ( ) {
System . out. println ( "异常抛出通知。。。报异常时执行" ) ;
}
@After ( "MyAdvice.pointcut()" )
public void after ( ) {
System . out. println ( "最终增强" ) ;
}
}
@Configuration
@ComponentScan ( "com.itheima" )
@EnableAspectJAutoProxy
public class SpringConfig {
}
@Test
public void aopTest2 ( ) {
ApplicationContext app2 = new AnnotationConfigApplicationContext ( SpringConfig . class ) ;
UserService userService = app2. getBean ( UserService . class ) ;
userService. show2 ( ) ;
}
@Service ( "service" )
public class UserServiceImpl implements UserService {
@Override
public void show1 ( ) {
System . out. println ( "show1......" ) ;
}
@Override
public void show2 ( ) {
System . out. println ( "show2......." ) ;
}
}
3.3 注解方式AOP原理解析
注解方式AOP原理解析
之前在使用xml配置AOP时,是借助的Spring的外部命名空间的加载方式完成的,使用注解配置后,就抛弃了
标签,而该标签最终加载了名为AspectJAwareAdvisorAutoProxyCreator
的BeanPostProcessor
,最终,在该BeanPostProcessor
中完成了代理对象的生成。
同样,从aspectj-autoproxy
标签的解析器入手
this . registerBeanDefinitionParser ( "aspectj-autoproxy" , new AspectJAutoProxyBeanDefinitionParser ( ) ) ;
之前在使用xml配置AOP时,是借助的Spring的外部命名空间的加载方式完成的,使用注解配置后,就抛弃了
标签,而该标签最终加载了名为AspectJAwareAdvisorAutoProxyCreator
的BeanPostProcessor
,最终,在该BeanPostProcessor
中完成了代理对象的生成。
< aop: aspectj-autoproxy/>
同样,从aspectj-autoproxy
标签解析器入手
this . registerBeanDefinitionParser ( "aspectj-autoproxy" , new AspectJAutoProxyBeanDefinitionParser ( ) ) ;
而AspectJAutoProxyBeanDefinitionParser代码内部,最终也是执行了和xml方式AOP一样的代码
registerOrEscalateApcAsRequired ( AnnotationAwareAspectJAutoProxyCreator . class , register, source) ;
如果使用的是核心配置类的话
@Configuration
@ComponentScan ( "com.itheima.aop" )
@EnableAspectJAutoProxy
public class ApplicationContextConfig ( ) {
}
查看@EnableAspectAutoProxy源码,使用的也是@Import导入相关解析类
@Target ( { ElementType . TYPE } )
@Retention ( RetentionPolicy . RUNTIME )
@Documented
@Import ( { AspectJAutoProxyRegistrar . class } )
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass ( ) default false ;
boolean exposeProxy ( ) default false ;
}
使用@Import导入的AspectJAutoProxyRegistrar源码,一路追踪下去,最终还是注册了AnnotationAwareAspectJAutoProxyCreator这个类
你可能感兴趣的:(spring,SSM框架,spring,java,后端)
移动端城市区县二级联动选择功能实现包
good2know
本文还有配套的精品资源,点击获取简介:本项目是一套为移动端设计的jQuery实现方案,用于简化用户在选择城市和区县时的流程。它包括所有必需文件:HTML、JavaScript、CSS及图片资源。通过动态更新下拉菜单选项,实现城市到区县的联动效果,支持数据异步加载。开发者可以轻松集成此功能到移动网站或应用,并可基于需求进行扩展和优化。1.jQuery移动端解决方案概述jQuery技术简介jQuery
SpringMVC执行流程(原理),通俗易懂
国服冰
SpringMVC spring mvc
SpringMVC执行流程(原理),通俗易懂一、图解SpringMVC流程二、进一步理解Springmvc的执行流程1、导入依赖2、建立展示的视图3、web.xml4、spring配置文件springmvc-servlet5、Controller6、tomcat配置7、访问的url8、视图页面一、图解SpringMVC流程图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提
深入解析JVM工作原理:从字节码到机器指令的全过程
一、JVM概述Java虚拟机(JVM)是Java平台的核心组件,它实现了Java"一次编写,到处运行"的理念。JVM是一个抽象的计算机器,它有自己的指令集和运行时内存管理机制。JVM的主要职责:加载:读取.class文件并验证其正确性存储:管理内存分配和垃圾回收执行:解释或编译字节码为机器指令安全:提供沙箱环境限制恶意代码二、JVM架构详解JVM由三个主要子系统组成:1.类加载子系统类加载过程分为
Spring进阶 - SpringMVC实现原理之DispatcherServlet处理请求的过程
倾听铃的声
后端 spring java mvc 开发语言 分布式
前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第二篇:DispatcherServlet处理请求的过程的源码解析。@pdaiSpring进阶-SpringMVC实现原理之DispatcherServlet处理请求的
JVM 内存模型深度解析:原子性、可见性与有序性的实现
练习时长两年半的程序员小胡
JVM 深度剖析:从面试考点到生产实践 jvm java 内存模型
在了解了JVM的基础架构和类加载机制后,我们需要进一步探索Java程序在多线程环境下的内存交互规则。JVM内存模型(JavaMemoryModel,JMM)定义了线程和主内存之间的抽象关系,它通过规范共享变量的访问方式,解决了多线程并发时的数据一致性问题。本文将从内存模型的核心目标出发,详解原子性、可见性、有序性的实现机制,以及volatile、synchronized等关键字在其中的作用。一、J
Flowable 高级扩展:自定义元素与性能优化实战
练习时长两年半的程序员小胡
Flowable 流程引擎实战指南 流程图 flowable BPMN 流程引擎 java
在前五篇文章中,我们从基础概念、流程设计、API实战、SpringBoot集成,到外部系统协同,逐步构建了Flowable的应用体系。但企业级复杂场景中,原生功能往往难以满足定制化需求——比如需要特殊的审批规则网关、与决策引擎联动实现动态路由,或是在高并发场景下优化流程引擎性能。本文将聚焦Flowable的高级扩展能力,详解如何自定义流程元素、集成规则引擎,并掌握大型系统中的性能调优策略。一、自定
Java | 多线程经典问题 - 售票
Ada54
一、售票需求1)同一个票池2)多个窗口卖票,不能出售同一张票二、售票问题代码实现(线程与进程小总结,请戳:Java|线程和进程,创建线程)step1:定义SaleWindow类实现Runnable接口,覆盖run方法step2:实例化SaleWindow对象,创建Thread对象,将SaleWindow作为参数传给Thread类的构造函数,然后通过Thread.start()方法启动线程step3
SpringMVC的执行流程
1、什么是MVCMVC是一种设计模式。MVC的原理图如下所示M-Model模型(完成业务逻辑:有javaBean构成,service+dao+entity)V-View视图(做界面的展示jsp,html……)C-Controller控制器(接收请求—>调用模型—>根据结果派发页面2、SpringMVC是什么SpringMVC是一个MVC的开源框架,SpringMVC=Struts2+Spring,
2018-09-27 aop相关
蒋超_58dc
1.静态织入,需要使用aspectj专用的compilermaven工程可以采用:https://www.mojohaus.org/aspectj-maven-plugin/2.动态织入,配合spring,创建代理来执行3.
JAVA接口机结构解析
秃狼
SpringBoot 八股文 Java java 学习
什么是接口机在Java项目中,接口机通常指用于与外部系统进行数据交互的中间层,负责处理请求和响应的转换、协议适配、数据格式转换等任务。接口机的结构我们的接口机的结构分为两个大部分,外部接口机和内部接口机,在业务的调度上也是通过mq来实现的,只要的目的就是为了解耦合和做差异化。在接口机中主要的方法就是定时任务,消息的发送和消费,其他平台调用接口机只能提供外部接口机的方法进行调用,外部接口机可以提供消
最新阿里四面面试真题46道:面试技巧+核心问题+面试心得
风平浪静如码
前言做技术的有一种资历,叫做通过了阿里的面试。这些阿里Java相关问题,都是之前通过不断优秀人才的铺垫总结的,先自己弄懂了再去阿里面试,不然就是去丢脸,被虐。希望对大家帮助,祝面试成功,有个更好的职业规划。一,阿里常见技术面1、微信红包怎么实现。2、海量数据分析。3、测试职位问的线程安全和非线程安全。4、HTTP2.0、thrift。5、面试电话沟通可能先让自我介绍。6、分布式事务一致性。7、ni
图论算法经典题目解析:DFS、BFS与拓扑排序实战
周童學
数据结构与算法 深度优先 算法 图论
图论算法经典题目解析:DFS、BFS与拓扑排序实战图论问题是算法面试中的高频考点,本博客将通过四道LeetCode经典题目(均来自"Top100Liked"题库),深入讲解图论的核心算法思想和实现技巧。涵盖DFS、BFS、拓扑排序和前缀树等知识点,每道题配有Java实现和易错点分析。1.岛屿数量(DFS遍历)问题描述给定一个由'1'(陆地)和'0'(水)组成的二维网格,计算岛屿的数量。岛屿由水平或
【异常】使用 LiteFlow 框架时,提示错误ChainDuplicateException: [chain name duplicate] chainName=categoryChallenge
本本本添哥
002 - 进阶开发能力 java
一、报错内容Causedby:com.yomahub.liteflow.exception.ChainDuplicateException:[chainnameduplicate]chainName=categoryChallengeatcom.yomahub.liteflow.parser.helper.ParserHelper.lambda$null$0(ParserHelper.java:1
Java并发核心:线程池使用技巧与最佳实践! | 多线程篇(五)
bug菌¹
Java实战(进阶版) java Java零基础入门 Java并发 线程池 多线程篇
本文收录于「Java进阶实战」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!环境说明:Windows10+IntelliJIDEA2021.3.2+Jdk1.8本文目录前言摘要正文何为线程池?为什么需要线程池?线程池的好处线程池使用场景如何创建线程池?线程池的常见配置源码解析案例分享案例代码演示案例运行
Java 队列
tryxr
java 开发语言 队列
队列一般用什么哪种结构实现队列的特性数据入队列时一定是从尾部插入吗数据出队列时一定是从头部删除吗队列的基本运算有什么队列支持随机访问吗队列的英文表示什么是队列队列从哪进、从哪出队列的进出顺序队列是用哪种结构实现的Queue和Deque有什么区别Queue接口的方法Queue中的add与offer的区别offer、poll、peek的模拟实现如何利用链表实现队列如何利用顺序表实现队列什么叫做双端队列
JVM 内存分配与回收策略:从对象创建到内存释放的全流程
在JVM的运行机制中,内存分配与回收策略是连接对象生命周期与垃圾收集器的桥梁。它决定了对象在堆内存中的创建位置、存活过程中的区域迁移,以及最终被回收的时机。合理的内存分配策略能减少GC频率、降低停顿时间,是优化Java应用性能的核心环节。本文将系统解析JVM的内存分配规则、对象晋升机制,以及实战中的内存优化技巧。一、对象优先在Eden区分配:新生代的“临时缓冲区”大多数情况下,Java对象在新生代
代码随想录算法训练营第三十五天
01背包问题二维题目链接01背包问题二维题解importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);intM=sc.nextInt();intN=sc.nextInt();int[]space=newint[M];int[]value=new
微信公众号回调java_处理微信公众号消息回调
weixin_39607620
微信公众号回调java
1、背景在上一节中,咱们知道如何接入微信公众号,可是以后公众号会与咱们进行交互,那么微信公众号如何通知到咱们本身的服务器呢?咱们知道咱们接入的时候提供的url是GET/mp/entry,那么公众号以后产生的事件将会以POST/mp/entry发送到咱们本身的服务器上。html2、代码实现,此处仍是使用weixin-java-mp这个框架实现一、引入weixin-java-mpcom.github.
[spring6: Mvc-网关]-源码解析
推荐阅读:[spring6:Mvc-函数式编程]-源码解析GatewayServerMvcAutoConfiguration@AutoConfiguration(after={HttpClientAutoConfiguration.class,RestTemplateAutoConfiguration.class,RestClientAutoConfiguration.class,FilterAu
学C++的五大惊人好处
为什么要学c++学c++有什么用学习c++的好处有1.中考可以加分2.高考可能直接录取3.就业广且工资高4.在未来30--50年c++一定是一个很受欢迎的职业5.c++成功的例子deepsick等AI智能C++语言兼备编程效率和编译运行效率的语言C++语言是C语言功能增强版,在c语言的基础上添加了面向对象编程和泛型编程的支持既继承了C语言高效,简洁,快速和可移植的传统,又具备类似Java、Go等其
Java8 Stream流的sorted()的排序【正序、倒序、多字段排序】
Tony666688888
java windows 开发语言
针对集合排序,java8可以用Stream流的sorted()进行排序。示例Bean以下我们会使用这个Bean来做示例。publicclassOrder{privateStringweight;privateDoubleprice;privateStringdateStr;//忽略getter、setter、构造方法、toString}字段排序首先是比较器Comparator,形式如下:Compa
用代码生成艺术字:设计个性化海报的秘密
本文围绕“用代码生成艺术字:设计个性化海报的秘密”展开,先概述代码生成艺术字在海报设计中的独特价值,接着介绍常用的代码工具(如HTML、CSS、JavaScript等),详细阐述从构思到实现的完整流程,包括字体样式设计、动态效果添加等,还分享了提升艺术字质感的技巧及实际案例。最后总结代码生成艺术字的优势,为设计师提供打造个性化海报的实用指南,助力提升海报设计的独特性与吸引力,符合搜索引擎SEO标准
java实习生40多天有感
别拿爱情当饭吃
从5月15日开始,我开始第一步步入社会,我今年大三,在一家上市互联网公司做一名实习生,主要做java后端开发。开始的时候,觉得公司的环境挺不错的,不过因为公司在CBD,所以隔壁的午饭和晚饭都要20+RMB,而且还吃不饱,这让我感觉挺郁闷的。一到下午,我就会犯困(因为饿)。因此,我又不得不买一些干粮在公司屯着。关于技术,有一个比较大的项目在需求调研当中,我们做实习生,就是辅助项目经理,测试功能,并且
大数据技术笔记—spring入门
卿卿老祖
篇一spring介绍spring.io官网快速开始Aop面向切面编程,可以任何位置,并且可以细致到方法上连接框架与框架Spring就是IOCAOP思想有效的组织中间层对象一般都是切入service层spring组成前后端分离已学方式,前后台未分离:Spring的远程通信:明日更新创建第一个spring项目来源:科多大数据
大学生入门:初识方法及其易踩坑的点
在java学习过程中,我们不难发现有很多重复使用的功能代码块,每次使用如果都要重新写一遍,岂不是很麻烦,就算是“cv”大法,感觉也不是很方便,那么,有什么办法可以解决这个问题呢?方法!java中,一段可重用的,用于执行特定功能的代码块叫做方法,它可以接收参数、返回结果,并且可以被多次使用。一、方法的基本结构[修饰符]返回值类型方法名([参数列表])[throws异常类型]{//方法体}[throw
[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
这些不会的
解释:这个错误是很常见的错误,错误的提示已经很清楚了就是java的Object数组不能转换成为String[]数组,这就说明你要转换的数组它本身是Object类型的数组,但是你却非要把它转换为String类的数组,这当然是错误的。示例:[java]viewplaincopypackagecom.dada;importjava.util.ArrayList;importjava.util.List;
HikariCP调试日志深度解析:生产环境故障排查完全指南
HikariCP调试日志深度解析:生产环境故障排查完全指南更新时间:2025年7月4日|作者:资深架构师|适用版本:HikariCP5.x+|难度等级:中高级前言在生产环境中,数据库连接池往往是系统性能的关键瓶颈。HikariCP作为当前最流行的Java连接池,其调试日志包含了丰富的运行时信息,能够帮助我们快速定位和解决各种连接池相关问题。本文将深入解析HikariCP的日志体系,提供一套完整的故
大学社团管理系统(11831)
codercode2022
java spring boot spring echarts spring cloud sentinel java-rocketmq
有需要的同学,源代码和配套文档领取,加文章最下方的名片哦一、项目演示项目演示视频二、资料介绍完整源代码(前后端源代码+SQL脚本)配套文档(LW+PPT+开题报告)远程调试控屏包运行三、技术介绍Java语言SSM框架SpringBoot框架Vue框架JSP页面Mysql数据库IDEA/Eclipse开发四、项目截图有需要的同学,源代码和配套文档领取,加文章最下方的名片哦!
今年校招竞争真激烈
12_05
程序员满大街,都要找不到工作了。即使人工智能满大街,我也后悔当初没学机器学习,后悔当初没学Java。C++真难找工作。难道毕了业就失业吗?好担心!
全面解析:Spring Gateway如何优雅处理微服务的路由转发?
万猫学社
gateway java spring
SpringGateway简介SpringGateway,这是一个基于Spring5、SpringBoot2和ProjectReactor的API网关。它旨在为微服务架构提供一个简单、有效的统一的API路由、限流、熔断等功能。在微服务的世界里,SpringGateway就像一个交通警察,负责指挥和引导各个微服务之间的交通。相较于其他的网关技术,比如Nginx、Zuul等,SpringGateway
解线性方程组
qiuwanchi
package gaodai.matrix;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Sc
在mysql内部存储代码
annan211
性能 mysql 存储过程 触发器
在mysql内部存储代码
在mysql内部存储代码,既有优点也有缺点,而且有人倡导有人反对。
先看优点:
1 她在服务器内部执行,离数据最近,另外在服务器上执行还可以节省带宽和网络延迟。
2 这是一种代码重用。可以方便的统一业务规则,保证某些行为的一致性,所以也可以提供一定的安全性。
3 可以简化代码的维护和版本更新。
4 可以帮助提升安全,比如提供更细
Android使用Asynchronous Http Client完成登录保存cookie的问题
hotsunshine
android
Asynchronous Http Client是android中非常好的异步请求工具
除了异步之外还有很多封装比如json的处理,cookie的处理
引用
Persistent Cookie Storage with PersistentCookieStore
This library also includes a PersistentCookieStore whi
java面试题
Array_06
java 面试
java面试题
第一,谈谈final, finally, finalize的区别。
final-修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能
网站加速
oloz
网站加速
前序:本人菜鸟,此文研究总结来源于互联网上的资料,大牛请勿喷!本人虚心学习,多指教.
1、减小网页体积的大小,尽量采用div+css模式,尽量避免复杂的页面结构,能简约就简约。
2、采用Gzip对网页进行压缩;
GZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNⅨ系统的文件压缩。我们在Linux中经常会用到后缀为.gz
正确书写单例模式
随意而生
java 设计模式 单例
单例模式算是设计模式中最容易理解,也是最容易手写代码的模式了吧。但是其中的坑却不少,所以也常作为面试题来考。本文主要对几种单例写法的整理,并分析其优缺点。很多都是一些老生常谈的问题,但如果你不知道如何创建一个线程安全的单例,不知道什么是双检锁,那这篇文章可能会帮助到你。
懒汉式,线程不安全
当被问到要实现一个单例模式时,很多人的第一反应是写出如下的代码,包括教科书上也是这样
单例模式
香水浓
java
懒汉 调用getInstance方法时实例化
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(null == ins
安装Apache问题:系统找不到指定的文件 No installed service named "Apache2"
AdyZhang
apache http server
安装Apache问题:系统找不到指定的文件 No installed service named "Apache2"
每次到这一步都很小心防它的端口冲突问题,结果,特意留出来的80端口就是不能用,烦。
解决方法确保几处:
1、停止IIS启动
2、把端口80改成其它 (譬如90,800,,,什么数字都好)
3、防火墙(关掉试试)
在运行处输入 cmd 回车,转到apa
如何在android 文件选择器中选择多个图片或者视频?
aijuans
android
我的android app有这样的需求,在进行照片和视频上传的时候,需要一次性的从照片/视频库选择多条进行上传
但是android原生态的sdk中,只能一个一个的进行选择和上传。
我想知道是否有其他的android上传库可以解决这个问题,提供一个多选的功能,可以使checkbox之类的,一次选择多个 处理方法
官方的图片选择器(但是不支持所有版本的androi,只支持API Level
mysql中查询生日提醒的日期相关的sql
baalwolf
mysql
SELECT sysid,user_name,birthday,listid,userhead_50,CONCAT(YEAR(CURDATE()),DATE_FORMAT(birthday,'-%m-%d')),CURDATE(), dayofyear( CONCAT(YEAR(CURDATE()),DATE_FORMAT(birthday,'-%m-%d')))-dayofyear(
MongoDB索引文件破坏后导致查询错误的问题
BigBird2012
mongodb
问题描述:
MongoDB在非正常情况下关闭时,可能会导致索引文件破坏,造成数据在更新时没有反映到索引上。
解决方案:
使用脚本,重建MongoDB所有表的索引。
var names = db.getCollectionNames();
for( var i in names ){
var name = names[i];
print(name);
Javascript Promise
bijian1013
JavaScript Promise
Parse JavaScript SDK现在提供了支持大多数异步方法的兼容jquery的Promises模式,那么这意味着什么呢,读完下文你就了解了。
一.认识Promises
“Promises”代表着在javascript程序里下一个伟大的范式,但是理解他们为什么如此伟大不是件简
[Zookeeper学习笔记九]Zookeeper源代码分析之Zookeeper构造过程
bit1129
zookeeper
Zookeeper重载了几个构造函数,其中构造者可以提供参数最多,可定制性最多的构造函数是
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolea
【Java命令三】jstack
bit1129
jstack
jstack是用于获得当前运行的Java程序所有的线程的运行情况(thread dump),不同于jmap用于获得memory dump
[hadoop@hadoop sbin]$ jstack
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F
jboss 5.1启停脚本 动静分离部署
ronin47
以前启动jboss,往各种xml配置文件,现只要运行一句脚本即可。start nohup sh /**/run.sh -c servicename -b ip -g clustername -u broatcast jboss.messaging.ServerPeerID=int -Djboss.service.binding.set=p
UI之如何打磨设计能力?
brotherlamp
UI ui教程 ui自学 ui资料 ui视频
在越来越拥挤的初创企业世界里,视觉设计的重要性往往可以与杀手级用户体验比肩。在许多情况下,尤其对于 Web 初创企业而言,这两者都是不可或缺的。前不久我们在《右脑革命:别学编程了,学艺术吧》中也曾发出过重视设计的呼吁。如何才能提高初创企业的设计能力呢?以下是 9 位创始人的体会。
1.找到自己的方式
如果你是设计师,要想提高技能可以去设计博客和展示好设计的网站如D-lists或
三色旗算法
bylijinnan
java 算法
import java.util.Arrays;
/**
问题:
假设有一条绳子,上面有红、白、蓝三种颜色的旗子,起初绳子上的旗子颜色并没有顺序,
您希望将之分类,并排列为蓝、白、红的顺序,要如何移动次数才会最少,注意您只能在绳
子上进行这个动作,而且一次只能调换两个旗子。
网上的解法大多类似:
在一条绳子上移动,在程式中也就意味只能使用一个阵列,而不使用其它的阵列来
警告:No configuration found for the specified action: \'s
chiangfai
configuration
1.index.jsp页面form标签未指定namespace属性。
<!--index.jsp代码-->
<%@taglib prefix="s" uri="/struts-tags"%>
...
<s:form action="submit" method="post"&g
redis -- hash_max_zipmap_entries设置过大有问题
chenchao051
redis hash
使用redis时为了使用hash追求更高的内存使用率,我们一般都用hash结构,并且有时候会把hash_max_zipmap_entries这个值设置的很大,很多资料也推荐设置到1000,默认设置为了512,但是这里有个坑
#define ZIPMAP_BIGLEN 254
#define ZIPMAP_END 255
/* Return th
select into outfile access deny问题
daizj
mysql txt 导出数据到文件
本文转自:http://hatemysql.com/2010/06/29/select-into-outfile-access-deny%E9%97%AE%E9%A2%98/
为应用建立了rnd的帐号,专门为他们查询线上数据库用的,当然,只有他们上了生产网络以后才能连上数据库,安全方面我们还是很注意的,呵呵。
授权的语句如下:
grant select on armory.* to rn
phpexcel导出excel表简单入门示例
dcj3sjt126com
PHP Excel phpexcel
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
if (PHP_SAPI == 'cli')
die('This example should only be run from a Web Brows
美国电影超短200句
dcj3sjt126com
电影
1. I see. 我明白了。2. I quit! 我不干了!3. Let go! 放手!4. Me too. 我也是。5. My god! 天哪!6. No way! 不行!7. Come on. 来吧(赶快)8. Hold on. 等一等。9. I agree。 我同意。10. Not bad. 还不错。11. Not yet. 还没。12. See you. 再见。13. Shut up!
Java访问远程服务
dyy_gusi
httpclient webservice get post
随着webService的崛起,我们开始中会越来越多的使用到访问远程webService服务。当然对于不同的webService框架一般都有自己的client包供使用,但是如果使用webService框架自己的client包,那么必然需要在自己的代码中引入它的包,如果同时调运了多个不同框架的webService,那么就需要同时引入多个不同的clien
Maven的settings.xml配置
geeksun
settings.xml
settings.xml是Maven的配置文件,下面解释一下其中的配置含义:
settings.xml存在于两个地方:
1.安装的地方:$M2_HOME/conf/settings.xml
2.用户的目录:${user.home}/.m2/settings.xml
前者又被叫做全局配置,后者被称为用户配置。如果两者都存在,它们的内容将被合并,并且用户范围的settings.xml优先。
ubuntu的init与系统服务设置
hongtoushizi
ubuntu
转载自:
http://iysm.net/?p=178 init
Init是位于/sbin/init的一个程序,它是在linux下,在系统启动过程中,初始化所有的设备驱动程序和数据结构等之后,由内核启动的一个用户级程序,并由此init程序进而完成系统的启动过程。
ubuntu与传统的linux略有不同,使用upstart完成系统的启动,但表面上仍维持init程序的形式。
运行
跟我学Nginx+Lua开发目录贴
jinnianshilongnian
nginx lua
使用Nginx+Lua开发近一年的时间,学习和实践了一些Nginx+Lua开发的架构,为了让更多人使用Nginx+Lua架构开发,利用春节期间总结了一份基本的学习教程,希望对大家有用。也欢迎谈探讨学习一些经验。
目录
第一章 安装Nginx+Lua开发环境
第二章 Nginx+Lua开发入门
第三章 Redis/SSDB+Twemproxy安装与使用
第四章 L
php位运算符注意事项
home198979
位运算 PHP &
$a = $b = $c = 0;
$a & $b = 1;
$b | $c = 1
问a,b,c最终为多少?
当看到这题时,我犯了一个低级错误,误 以为位运算符会改变变量的值。所以得出结果是1 1 0
但是位运算符是不会改变变量的值的,例如:
$a=1;$b=2;
$a&$b;
这样a,b的值不会有任何改变
Linux shell数组建立和使用技巧
pda158
linux
1.数组定义 [chengmo@centos5 ~]$ a=(1 2 3 4 5) [chengmo@centos5 ~]$ echo $a 1 一对括号表示是数组,数组元素用“空格”符号分割开。
2.数组读取与赋值 得到长度: [chengmo@centos5 ~]$ echo ${#a[@]} 5 用${#数组名[@或
hotspot源码(JDK7)
ol_beta
java HotSpot jvm
源码结构图,方便理解:
├─agent Serviceab
Oracle基本事务和ForAll执行批量DML练习
vipbooks
oracle sql
基本事务的使用:
从账户一的余额中转100到账户二的余额中去,如果账户二不存在或账户一中的余额不足100则整笔交易回滚
select * from account;
-- 创建一张账户表
create table account(
-- 账户ID
id number(3) not null,
-- 账户名称
nam