- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
更新为使用附加信息重新表述问题
我们有两个注解:
CustomLogging
PollableStreamListener
CustomLogging
注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomLogging {
}
CustomLoggingAspect
类(class):
@Aspect
@Component
@Slf4j
@Order(value = 1)
public class CustomLoggingAspect {
@Before("@annotation(customLogging)")
public void addCustomLogging(CustomLogging customLogging) {
log.info("Logging some information");
}
}
PollableStreamListener
注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PollableStreamListener {
}
PollableStreamListenerAspect
类(class):
@Aspect
@Component
@Slf4j
public class PollableStreamListenerAspect {
private final ExecutorService executor = Executors.newFixedThreadPool(1);
private volatile boolean paused = false;
@Around(value = "@annotation(pollableStreamListener) && args(dataCapsule,..)")
public void receiveMessage(ProceedingJoinPoint joinPoint,
PollableStreamListener pollableStreamListener, Object dataCapsule) {
if (dataCapsule instanceof Message) {
Message<?> message = (Message<?>) dataCapsule;
AcknowledgmentCallback callback = StaticMessageHeaderAccessor
.getAcknowledgmentCallback(message);
callback.noAutoAck();
if (!paused) {
// The separate thread is not busy with a previous message, so process this message:
Runnable runnable = () -> {
try {
paused = true;
// Call method to process this Kafka message
joinPoint.proceed();
callback.acknowledge(Status.ACCEPT);
} catch (Throwable e) {
callback.acknowledge(Status.REJECT);
throw new PollableStreamListenerException(e);
} finally {
paused = false;
}
};
executor.submit(runnable);
} else {
// The separate thread is busy with a previous message, so re-queue this message for later:
callback.acknowledge(Status.REQUEUE);
log.info("Re-queue");
}
}
}
}
我们有一个名为
CleanupController
的类根据计划定期执行。
CleanupController
类(class):
@Scheduled(fixedDelayString = "${app.pollable-consumer.time-interval}")
public void pollForDeletionRequest() {
log.trace("Polling for new messages");
cleanupInput.poll(cleanupSubmissionService::submitDeletion);
}
当调度执行时,它会调用另一个类中的一个方法,该方法用
PollableStreamListener
注释。和
CustomLogging
.我添加了
Thread.sleep()
模仿需要一段时间执行的方法。
@PollableStreamListener
@CustomLogging
public void submitDeletion(Message<?> received) {
try {
log.info("Starting processing");
Thread.sleep(10000);
log.info("Finished processing");
} catch (Exception e) {
log.info("Error", e);
}
}
我面临的问题是
CustomLogging
产生的输出每次我们使用
@Schedule
轮询新消息时打印,但我只希望它在实际执行带注释的方法时打印(这可能现在发生,也可能在将来发生,具体取决于当前是否正在处理另一条消息)。这会导致令人困惑的日志消息,因为这意味着该消息现在正在被处理,而实际上它已被重新排队以供将来执行。
CustomLogging
仅当带注释的方法执行时才会发生输出?
@Order
在 PollableStreamListener
PollableStreamListenerAspect
上设置 1 的顺序:
@Aspect
@Component
@Slf4j
@Order(value = 1)
public class PollableStreamListenerAspect {
...
}
将
CustomLoggingAspect
的顺序增加到 2 :
@Aspect
@Component
@Slf4j
@Order(value = 2)
public class CustomLoggingAspect {
...
}
我发现在进行这些更改后,轮询根本无法检测到新请求。这是
PollableStreamListenerAspect
上的更改这引入了这个问题(我注释掉了那行并重新运行它,事情的表现和以前一样)。
@Order(value = Ordered.HIGHEST_PRECEDENCE)
在 PollableStreamListener
PollableStreamListener
使用
HIGHEST_PRECEDENCE
并更新
@Around
值(value):
@Aspect
@Component
@Slf4j
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class PollableStreamListenerAspect {
private final ExecutorService executor = Executors.newFixedThreadPool(1);
private volatile boolean paused = false;
@Around(value = "@annotation(au.com.brolly.commons.stream.PollableStreamListener)")
public void receiveMessage(ProceedingJoinPoint joinPoint) {
if (!paused) {
// The separate thread is not busy with a previous message, so process this message:
Runnable runnable = () -> {
try {
paused = true;
// Call method to process this Kafka message
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
throw new PollableStreamListenerException(e);
} finally {
paused = false;
}
};
executor.submit(runnable);
} else {
// The separate thread is busy with a previous message, so re-queue this message for later:
log.info("Re-queue");
}
}
}
这现在部分工作。当我发送 Kafka 消息时,它会被处理,并且来自
CustomLogging
的日志记录只有在没有处理另一条 Kafka 消息时才会打印注释。到现在为止还挺好。
@Around
接受
Message
这是通过 Kafka 提供的。我尝试使用上面的示例更改以下行:
@Around(value = "@annotation(au.com.brolly.commons.stream.PollableStreamListener) && args(dataCapsule,..)")
public void receiveMessage(ProceedingJoinPoint joinPoint, Object dataCapsule) {
...
}
服务器正确启动,但是当我发布 Kafka 消息时,出现以下异常:
2021-04-22 10:38:00,055 ERROR [scheduling-1] org.springframework.core.log.LogAccessor: org.springframework.messaging.MessageHandlingException: nested exception is java.lang.IllegalStateException: Required to bind 2 arguments, but only bound 1 (JoinPointMatch was NOT bound in invocation), failedMessage=GenericMessage...
at org.springframework.cloud.stream.binder.DefaultPollableMessageSource.doHandleMessage(DefaultPollableMessageSource.java:330)
at org.springframework.cloud.stream.binder.DefaultPollableMessageSource.handle(DefaultPollableMessageSource.java:361)
at org.springframework.cloud.stream.binder.DefaultPollableMessageSource.poll(DefaultPollableMessageSource.java:219)
at org.springframework.cloud.stream.binder.DefaultPollableMessageSource.poll(DefaultPollableMessageSource.java:200)
at org.springframework.cloud.stream.binder.DefaultPollableMessageSource.poll(DefaultPollableMessageSource.java:68)
at xyx.pollForDeletionRequest(CleanupController.java:35)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalStateException: Required to bind 2 arguments, but only bound 1 (JoinPointMatch was NOT bound in invocation)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.argBinding(AbstractAspectJAdvice.java:596)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
at xyz.CleanupSubmissionServiceImpl$$EnhancerBySpringCGLIB$$8737f6f8.submitDeletion(<generated>)
at org.springframework.cloud.stream.binder.DefaultPollableMessageSource.doHandleMessage(DefaultPollableMessageSource.java:327)
... 17 more
最佳答案
因为this problem , 你需要使用 @Order(value = Ordered.HIGHEST_PRECEDENCE)
在 PollableStreamListenerAspect
.确实很奇怪,但是它可以按您的意愿工作。不过,IMO 这个问题应该在 Spring 得到解决。不得不使用这个变通方法是丑陋的,只有当你的方面调用 proceed()
时才有效。异步实际上确实具有最高优先级,但并非总是如此。作为替代方案,您可以使用 native AspectJ 及其自己的声明建议优先级的概念,该概念独立于 Spring 内部。
这是您的应用程序的简化版本 MCVE :
注释:
package de.scrum_master.spring.q67155048;
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 CustomLogging {}
package de.scrum_master.spring.q67155048;
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 PollableStreamListener {}
带有带有两个注解的方法的组件:
package de.scrum_master.spring.q67155048;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
private int counter = 0;
@PollableStreamListener
@CustomLogging
public void submitDeletion() {
try {
System.out.println(" Starting processing #" + ++counter);
Thread.sleep(1000);
System.out.println(" Finished processing #" + counter);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
方面:
package de.scrum_master.spring.q67155048;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class CustomLoggingAspect {
@Before("@annotation(de.scrum_master.spring.q67155048.CustomLogging)")
public void addCustomLogging() {
System.out.println("Logging");
}
}
package de.scrum_master.spring.q67155048;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Aspect
@Component
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class PollableStreamListenerAspect {
public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(1);
private volatile boolean paused = false;
@Around("@annotation(de.scrum_master.spring.q67155048.PollableStreamListener)")
public void receiveMessage(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Receiving message");
if (!paused) {
// The separate thread is not busy with a previous message, so process this message:
Runnable runnable = () -> {
try {
paused = true;
joinPoint.proceed();
}
catch (Throwable throwable) {
throwable.printStackTrace();
}
finally {
paused = false;
}
};
EXECUTOR_SERVICE.submit(runnable);
}
else {
System.out.println(" Re-queue");
}
}
}
驱动申请:
package de.scrum_master.spring.q67155048;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
@Configuration
public class DemoApplication {
public static void main(String[] args) throws InterruptedException {
try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) throws InterruptedException {
MyComponent myComponent = appContext.getBean(MyComponent.class);
for (int i = 0; i < 10; i++) {
myComponent.submitDeletion();
Thread.sleep(500);
}
// This is just to make the application exit cleanly
PollableStreamListenerAspect.EXECUTOR_SERVICE.shutdown();
}
}
控制台日志:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.8.RELEASE)
2021-04-20 12:56:03.675 INFO 13560 --- [ main] d.s.spring.q67155048.DemoApplication : Starting DemoApplication on Xander-Ultrabook with PID 13560 (C:\Users\alexa\Documents\java-src\spring-aop-playground\target\classes started by alexa in C:\Users\alexa\Documents\java-src\spring-aop-playground)
...
2021-04-20 12:56:07.666 INFO 13560 --- [ main] d.s.spring.q67155048.DemoApplication : Started DemoApplication in 4.65 seconds (JVM running for 7.181)
Receiving message
Logging
Starting processing #1
Receiving message
Re-queue
Finished processing #1
Receiving message
Logging
Starting processing #2
Receiving message
Re-queue
Finished processing #2
Receiving message
Logging
Starting processing #3
Receiving message
Re-queue
Finished processing #3
Receiving message
Logging
Starting processing #4
Receiving message
Re-queue
Finished processing #4
Receiving message
Logging
Starting processing #5
Receiving message
Re-queue
Finished processing #5
2021-04-20 12:56:12.767 INFO 13560 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
...
看?我们计算 10 倍“接收消息”,但只有 5 倍“重新排队”和 5 倍“记录”。请注意,我对处理调用进行了编号,因为它们是异步的。这样,他们开始和结束时就更容易理解。
package de.scrum_master.spring.q67155048;
public class Message<T> {
private T content;
public Message(T content) {
this.content = content;
}
@Override
public String toString() {
return "Message{" +
"content=" + content +
'}';
}
}
package de.scrum_master.spring.q67155048;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
@Configuration
public class DemoApplication {
public static void main(String[] args) throws InterruptedException {
try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) throws InterruptedException {
MyComponent myComponent = appContext.getBean(MyComponent.class);
Message<String> message = new Message<>("Hi there!");
for (int i = 0; i < 10; i++) {
myComponent.submitDeletion(message);
Thread.sleep(500);
}
// This is just to make the application exit cleanly
PollableStreamListenerAspect.EXECUTOR_SERVICE.shutdown();
}
}
package de.scrum_master.spring.q67155048;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Aspect
@Component
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class PollableStreamListenerAspect {
public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(1);
private volatile boolean paused = false;
@Around("@annotation(de.scrum_master.spring.q67155048.PollableStreamListener) && args(dataCapsule, ..)")
public void receiveMessage(ProceedingJoinPoint joinPoint, Object dataCapsule) throws Throwable {
System.out.println("Receiving message");
if (!paused) {
// The separate thread is not busy with a previous message, so process this message:
Runnable runnable = () -> {
try {
paused = true;
System.out.println("dataCapsule = " + dataCapsule);
joinPoint.proceed();
}
catch (Throwable throwable) {
throwable.printStackTrace();
}
finally {
paused = false;
}
};
EXECUTOR_SERVICE.submit(runnable);
}
else {
System.out.println(" Re-queue");
}
}
}
根据您自己的经验,这会产生:
Exception in thread "main" java.lang.IllegalStateException: Required to bind 2 arguments, but only bound 1 (JoinPointMatch was NOT bound in invocation)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.argBinding(AbstractAspectJAdvice.java:605)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at de.scrum_master.spring.q67155048.MyComponent$$EnhancerBySpringCGLIB$$4baa410d.submitDeletion(<generated>)
at de.scrum_master.spring.q67155048.DemoApplication.doStuff(DemoApplication.java:21)
at de.scrum_master.spring.q67155048.DemoApplication.main(DemoApplication.java:13)
您正在点击
this problem ,我已经评论了关闭的
Spring issue #16956关于它,希望得到它repoened和有人修复它。
JoinPoint.getArgs()
手动获取参数。 :
package de.scrum_master.spring.q67155048;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Aspect
@Component
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class PollableStreamListenerAspect {
public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(1);
private volatile boolean paused = false;
//@Around("@annotation(de.scrum_master.spring.q67155048.PollableStreamListener) && args(dataCapsule, ..)")
@Around("@annotation(de.scrum_master.spring.q67155048.PollableStreamListener) && execution(* *(*, ..))")
//public void receiveMessage(ProceedingJoinPoint joinPoint, Object dataCapsule) throws Throwable {
public void receiveMessage(ProceedingJoinPoint joinPoint) throws Throwable {
Object dataCapsule = joinPoint.getArgs()[0];
System.out.println("Receiving message");
if (!paused) {
// The separate thread is not busy with a previous message, so process this message:
Runnable runnable = () -> {
try {
paused = true;
System.out.println("dataCapsule = " + dataCapsule);
joinPoint.proceed();
}
catch (Throwable throwable) {
throwable.printStackTrace();
}
finally {
paused = false;
}
};
EXECUTOR_SERVICE.submit(runnable);
}
else {
System.out.println(" Re-queue");
}
}
}
现在它再次像这样工作:
Receiving message
dataCapsule = Message{content=Hi there!}
Logging
Starting processing #1, message = Message{content=Hi there!}
Receiving message
Re-queue
Receiving message
Re-queue
Finished processing #1, message = Message{content=Hi there!}
Receiving message
dataCapsule = Message{content=Hi there!}
Logging
Starting processing #2, message = Message{content=Hi there!}
Receiving message
Re-queue
Finished processing #2, message = Message{content=Hi there!}
Receiving message
dataCapsule = Message{content=Hi there!}
Logging
Starting processing #3, message = Message{content=Hi there!}
Receiving message
Re-queue
Finished processing #3, message = Message{content=Hi there!}
Receiving message
dataCapsule = Message{content=Hi there!}
Logging
Starting processing #4, message = Message{content=Hi there!}
Receiving message
Re-queue
Finished processing #4, message = Message{content=Hi there!}
Receiving message
dataCapsule = Message{content=Hi there!}
Logging
Starting processing #5, message = Message{content=Hi there!}
关于java - 当一个@Around 建议没有进行时的建议优先级问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67155048/
int x = 1; System.out.println( x++ + x++ * --x ); 上面的代码打印出“5”,但我不明白怎么办?我一直为最后一个 x 取零,然后乘以仍然为 0 的第二个
我现在正在尝试使用 Preference 类 首选项 pfrOfThis = Preferences.userNodeForPackage(this) 出现错误: “类 java.util.prefs
用下面的代码 import sys print "Hello " + sys.argv[1] if len(sys.argv) > 1 else "Joe" + "." 当我运行时 python he
我的网页包含: td { padding-left:10px; } 引用的样式表包含: .rightColumn * {margin: 0; padding: 0;} 我在 rightc
使用 JPA 我有一个关于 CascadeTypes 的问题。 例如: @ManyToMany(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST,
下面的“括号”是怎么写的? val words = List("foo", "bar", "baz") val phrase = "These are upper case: " + words ma
我只是想知道,对于以下代码,编译器是否单独使用关联性/优先级或其他一些逻辑来评估。 int i = 0, k = 0; i = k++; 如果我们根据关联性和优先级进行评估,postfix ++具有比
我设置了一个 Azure FrontDoor 服务,以主/备份类型的方式将流量分配给两个 API 管理服务。就像我希望所有流量都流向我的主要 APIM 服务一样,如果我碰巧关闭该服务(假装中断),那么
这是一个简单的 CSS: /* Smartphones (portrait and landscape) ----------- */ @media only screen and (min-devi
我设置了一个 Azure FrontDoor 服务,以主/备份类型的方式将流量分配给两个 API 管理服务。就像我希望所有流量都流向我的主要 APIM 服务一样,如果我碰巧关闭该服务(假装中断),那么
来自 Programming Perl pg 90,他说: @ary = (1, 3, sort 4, 2); print @ary; 排序右侧的逗号在排序之前求值,而左侧的逗号在排序之
+----+------------+------+ | id | title | lang | +----+------------+------+ | 1 | title 1 EN |
如何使用 Java 获取 DiffServe 代码点 (DSCP) 整数的优先级部分?我预计它涉及位移位,但由于某种原因,我似乎无法获得我期望的值。 最佳答案 假设我理解正确,只需向右执行 3 位逻辑
我有下一个运行良好的 js 函数: $(function () { $(".country").click(function () { var countries = Arra
int a[3]={10,20,30}; int* p = a; cout << *p++ << endl; 根据 wikipedia ,后缀++的优先级高于解引用,*p++应该先运行p++再解引用结
我想在优先读取归档后解决这种类型的表达式 2+3/5*9+3-4 这是我尝试解决该任务的代码我该如何解决这个问题 while ( !inputFile.eof() ) { getline( inp
我正在玩 Rhino 并注意到这种奇怪的行为似乎是运算符优先级: js> {}+{} NaN js> ''+{}+{} [object Object][object Object] js> ''+({
我想遍历文件列表并检查它们是否存在,如果文件不存在则给出错误并退出。我写了下面的代码: FILES=( file1.txt file2.txt file3.txt ) for file in ${FI
我正在执行级联 SELECT: SELECT * FROM x WHERE a = 1 AND b = 2 AND c = 3 => If nothing found, try: SELECT * F
即将参加考试,我正在参加之前的考试。 问题: 当两个或多个样式表规则应用于同一元素时,以下哪种类型的规则将优先? 一个。任何来自浏览器的声明 b.有用户来源的正常声明 C。作者来源正常声明 d.文档级
我是一名优秀的程序员,十分优秀!